From a3c8adfdf6e64879c751cf3c0794471bcb0a45dc Mon Sep 17 00:00:00 2001 From: Henrik Levkowetz Date: Wed, 2 Oct 2013 21:53:28 +0000 Subject: [PATCH] Merged in the contents of commit [6337] from mcr@sandelman.ca, with some changes to take out dead code that inadvertently came back in. - Legacy-Id: 6344 Note: SVN reference [6337] has been migrated to Git commit d0d1d949a9328da6c4e30d8f5e0d14ffb204e678 --- changelog | 48 + ietf/group/models.py | 12 +- ietf/meeting/ajax.py | 53 +- ietf/meeting/fixtures/constraint83.json | 8 +- ietf/meeting/helpers.py | 15 + .../migrations/0010_add_recorded_badness.py | 347 ++++++++ ietf/meeting/migrations/0011_bepresent.py | 352 ++++++++ ...auto__add_field_scheduledsession_pinned.py | 317 +++++++ ietf/meeting/models.py | 379 +++++++- ietf/meeting/tests/agenda-83-txt-output.txt | 1 + ietf/meeting/tests/agenda-83-utc-output.html | 4 +- ietf/meeting/tests/agenda.py | 15 +- ietf/meeting/tests/api.py | 83 +- ietf/meeting/urls.py | 3 + ietf/meeting/views.py | 60 +- ietf/name/fixtures/names.xml | 6 + ietf/name/generate_fixtures.py | 0 .../0017_add_ispresent_constraint_name.py | 185 ++++ ietf/person/ajax.py | 22 + ietf/person/fixtures/person.json | 265 ++++++ ietf/person/models.py | 26 +- ietf/person/urls.py | 2 + ietf/templates/liaisons/field_help.html | 0 ietf/templates/liaisons/guide_from_ietf.html | 0 ietf/templates/liaisons/guide_to_ietf.html | 0 ietf/templates/meeting/agenda_list.html | 8 +- ietf/templates/meeting/landscape_edit.html | 178 ++-- ietf/templates/meeting/properties_edit.html | 8 +- ietf/templates/meeting/timeslot_edit.html | 10 +- static/css/agenda.css | 178 +++- static/images/conflict-boxes/ad1.xcf | Bin 0 -> 1913 bytes static/images/conflict-boxes/me1.png | Bin 0 -> 203 bytes static/images/conflict-boxes/me1.xcf | Bin 0 -> 1034 bytes static/images/conflict-boxes/narow1.png | Bin 0 -> 199 bytes static/images/conflict-boxes/narow1.xcf | Bin 0 -> 803 bytes static/images/conflict-boxes/narow2.png | Bin 0 -> 200 bytes static/images/conflict-boxes/narow2.xcf | Bin 0 -> 963 bytes static/images/conflict-boxes/narow2b.xcf | Bin 0 -> 803 bytes static/images/conflict-boxes/narow3.png | Bin 0 -> 195 bytes static/images/conflict-boxes/narow3.xcf | Bin 0 -> 967 bytes static/images/conflict-boxes/narrow1.png | Bin 0 -> 198 bytes static/images/conflict-boxes/narrow1.xcf | Bin 0 -> 1025 bytes static/js/{ => agenda}/agenda_edit.js | 30 +- static/js/{ => agenda}/agenda_helpers.js | 107 ++- static/js/{ => agenda}/agenda_listeners.js | 398 +++++---- static/js/{ => agenda}/agenda_objects.js | 837 +++++++++++++----- .../js/{ => agenda}/agenda_properties_edit.js | 0 .../js/{ => agenda}/agenda_property_utils.js | 0 static/js/{ => agenda}/agendas_edit.js | 0 static/js/{ => agenda}/timeslot_edit.js | 3 +- 50 files changed, 3331 insertions(+), 629 deletions(-) create mode 100644 ietf/meeting/migrations/0010_add_recorded_badness.py create mode 100644 ietf/meeting/migrations/0011_bepresent.py create mode 100644 ietf/meeting/migrations/0012_auto__add_field_scheduledsession_pinned.py mode change 100755 => 100644 ietf/name/generate_fixtures.py create mode 100644 ietf/name/migrations/0017_add_ispresent_constraint_name.py create mode 100644 ietf/person/ajax.py create mode 100644 ietf/person/fixtures/person.json mode change 100755 => 100644 ietf/templates/liaisons/field_help.html mode change 100755 => 100644 ietf/templates/liaisons/guide_from_ietf.html mode change 100755 => 100644 ietf/templates/liaisons/guide_to_ietf.html create mode 100644 static/images/conflict-boxes/ad1.xcf create mode 100644 static/images/conflict-boxes/me1.png create mode 100644 static/images/conflict-boxes/me1.xcf create mode 100644 static/images/conflict-boxes/narow1.png create mode 100644 static/images/conflict-boxes/narow1.xcf create mode 100644 static/images/conflict-boxes/narow2.png create mode 100644 static/images/conflict-boxes/narow2.xcf create mode 100644 static/images/conflict-boxes/narow2b.xcf create mode 100644 static/images/conflict-boxes/narow3.png create mode 100644 static/images/conflict-boxes/narow3.xcf create mode 100644 static/images/conflict-boxes/narrow1.png create mode 100644 static/images/conflict-boxes/narrow1.xcf rename static/js/{ => agenda}/agenda_edit.js (88%) rename static/js/{ => agenda}/agenda_helpers.js (83%) rename static/js/{ => agenda}/agenda_listeners.js (75%) rename static/js/{ => agenda}/agenda_objects.js (51%) rename static/js/{ => agenda}/agenda_properties_edit.js (100%) rename static/js/{ => agenda}/agenda_property_utils.js (100%) rename static/js/{ => agenda}/agendas_edit.js (100%) rename static/js/{ => agenda}/timeslot_edit.js (98%) diff --git a/changelog b/changelog index a06729805..a2db2c37e 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,51 @@ +ietfdb (4.80) ietf; urgench=high + + This is a major release which provides the code drop from phase 3 of the + Agenda Scheduling Tool. The code has been merged in, and a lot of minor + alignments done. Deployment of this will make the phase 3 agenda editing + tools available from the main ietf site, will align the database schema with + that used in the ongoing development work, and will provide the correct + models for secretariat tool adaptations. + + * Reworked the TestCase code and fixture loading substantially, resulting + in a substantial speed increase for tests when run on a transaction- + capable database engine. + + * Added an index page for nomcoms, at /nomcom/, with links to nomcom + pages and announcements, where they exist. + + * Fixed some bugs in the EncryptedTextField class. + + * Fixed the language of the nomination confirmation message. + + * Changed 'requirement' to 'desired expertise' in user-visible places in + the nomcom app. + + * Fixed a wrong secretariat template extension name. + + * Provide the missing safe_rep function required in the back-ported + assertIsNone() test case method. + + * Added an explanatory paragraph to the Desired Expertise page. + + * The exception string for submission upload read errors seems to have + changed after we switched to wsgi, from "Client read error" to "request + data read error". Now looking for just "read error". + + * Tweaked the introductory text on the Desired Expertise page. + + * Added a makefixture management command, from + http://djangosnippets.org/snippets/918/, somewhat hacked. + + * Updated fixtures, built to be more internally consistent in order to be + able to pre-load them for the test suite. + + * Fixed the manyfold duplicated position names in the position selection + drop-down list in the nomcom private index page. Fixes issue #1137. + + -- Henrik Levkowetz 01 Oct 2013 16:54:16 +0200 + + ietfdb (4.72) ietf; urgency=medium * Added a migration for a new ConstraintName field: penalty diff --git a/ietf/group/models.py b/ietf/group/models.py index 6468a41c6..1f70f2e1c 100644 --- a/ietf/group/models.py +++ b/ietf/group/models.py @@ -11,7 +11,7 @@ from ietf.group.colors import fg_group_colors, bg_group_colors import datetime import debug - + class GroupInfo(models.Model): time = models.DateTimeField(default=datetime.datetime.now) name = models.CharField(max_length=80) @@ -101,10 +101,14 @@ class Group(GroupInfo): group1['name'] = self.name group1['state'] = self.state.slug group1['type'] = self.type.slug - group1['parent_href'] = urljoin(host_scheme, self.parent.json_url()) + if self.parent is not None: + group1['parent_href'] = urljoin(host_scheme, self.parent.json_url()) # uncomment when people URL handle is created - #if self.ad is not None: - # group1['ad_href'] = urljoin(host_scheme, self.ad.url()) + try: + if self.ad is not None: + group1['ad_href'] = urljoin(host_scheme, self.ad.json_url()) + except Person.DoesNotExist: + pass group1['list_email'] = self.list_email group1['list_subscribe'] = self.list_subscribe group1['list_archive'] = self.list_archive diff --git a/ietf/meeting/ajax.py b/ietf/meeting/ajax.py index 12f0f41d8..16522ac3d 100644 --- a/ietf/meeting/ajax.py +++ b/ietf/meeting/ajax.py @@ -28,8 +28,13 @@ from ietf.settings import LOG_DIR log = logging.getLogger(__name__) +import debug + @dajaxice_register def readonly(request, meeting_num, schedule_id): + debug.say('readonly()') + debug.show('meeting_num') + debug.show('schedule_id') meeting = get_meeting(meeting_num) schedule = get_schedule_by_id(meeting, schedule_id) @@ -61,6 +66,30 @@ def readonly(request, meeting_num, schedule_id): 'owner_href': request.build_absolute_uri(schedule.owner.json_url()), 'read_only': read_only}) +@group_required('Area Director','Secretariat') +@dajaxice_register +def update_timeslot_pinned(request, schedule_id, scheduledsession_id, pinned=False): + schedule = get_object_or_404(Schedule, pk = int(schedule_id)) + meeting = schedule.meeting + cansee,canedit = agenda_permissions(meeting, schedule, request.user) + + if not canedit: + raise Http403 + return json.dumps({'error':'no permission'}) + + if scheduledsession_id is not None: + ss_id = int(scheduledsession_id) + + if ss_id != 0: + ss = get_object_or_404(schedule.scheduledsession_set, pk=ss_id) + + ss.pinned = pinned + ss.save() + + return json.dumps({'message':'valid'}) + + + @group_required('Area Director','Secretariat') @dajaxice_register def update_timeslot(request, schedule_id, session_id, scheduledsession_id=None, extended_from_id=None, duplicate=False): @@ -458,7 +487,10 @@ def session_json(request, num, sessionid): try: session = meeting.session_set.get(pk=int(sessionid)) except Session.DoesNotExist: - return json.dumps({'error':"no such session %s" % sessionid}) +# return json.dumps({'error':"no such session %s" % sessionid}) + return HttpResponse(json.dumps({'error':"no such session %s" % sessionid}), + status = 404, + mimetype="application/json") sess1 = session.json_dict(request.build_absolute_uri('/')) return HttpResponse(json.dumps(sess1, sort_keys=True, indent=2), @@ -466,6 +498,25 @@ def session_json(request, num, sessionid): # Would like to cache for 1 day, but there are invalidation issues. #@cache_page(86400) +def constraint_json(request, num, constraintid): + meeting = get_meeting(num) + + try: + constraint = meeting.constraint_set.get(pk=int(constraintid)) + except Constraint.DoesNotExist: + return HttpResponse(json.dumps({'error':"no such constraint %s" % constraintid}), + status = 404, + mimetype="application/json") + + json1 = constraint.json_dict(request.get_host_protocol()) + return HttpResponse(json.dumps(json1, sort_keys=True, indent=2), + mimetype="application/json") + + +# Cache for 2 hour2 +#@cache_page(7200) +# caching is a problem if there Host: header changes. +# def session_constraints(request, num, sessionid): meeting = get_meeting(num) diff --git a/ietf/meeting/fixtures/constraint83.json b/ietf/meeting/fixtures/constraint83.json index edb63cbca..43fa5f36b 100644 --- a/ietf/meeting/fixtures/constraint83.json +++ b/ietf/meeting/fixtures/constraint83.json @@ -1454,5 +1454,9 @@ {"pk": 22491, "model": "meeting.constraint", "fields": {"source": 1847, "meeting": 83, "target": 1751, "name": "conflic2"}}, {"pk": 22492, "model": "meeting.constraint", "fields": {"source": 1847, "meeting": 83, "target": 1817, "name": "conflic2"}}, {"pk": 22493, "model": "meeting.constraint", "fields": {"source": 1847, "meeting": 83, "target": 1728, "name": "conflic2"}}, -{"pk": 22494, "model": "meeting.constraint", "fields": {"source": 1847, "meeting": 83, "target": 1789, "name": "conflic2"}} -] \ No newline at end of file +{"pk": 22494, "model": "meeting.constraint", "fields": {"source": 1847, "meeting": 83, "target": 1789, "name": "conflic2"}}, +{"pk": 23000, "model": "meeting.constraint", "fields": {"source": 1816, "meeting": 83, "name": "bethere", "person": 103539}}, +{"pk": 23001, "model": "meeting.constraint", "fields": {"source": 1816, "meeting": 83, "name": "bethere", "person": 108554}}, +{"pk": 23002, "model": "meeting.constraint", "fields": {"source": 1816, "meeting": 83, "name": "bethere", "person": 102830}} + +] diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py index 4e07639d1..59bc9036f 100644 --- a/ietf/meeting/helpers.py +++ b/ietf/meeting/helpers.py @@ -10,8 +10,11 @@ from tempfile import mkstemp from django import forms from django.http import Http404 +from django.http import HttpRequest from django.db.models import Max, Q from django.conf import settings +from django.core.cache import cache +from django.utils.cache import get_cache_key import debug import urllib @@ -344,3 +347,15 @@ def agenda_permissions(meeting, schedule, user): canedit = True return cansee,canedit + +def session_constraint_expire(session): + from django.core.urlresolvers import reverse + from ajax import session_constraints + path = reverse(session_constraints, args=[session.meeting.number, session.pk]) + request = HttpRequest() + request.path = path + key = get_cache_key(request) + if key is not None and cache.has_key(key): + cache.delete(key) + + diff --git a/ietf/meeting/migrations/0010_add_recorded_badness.py b/ietf/meeting/migrations/0010_add_recorded_badness.py new file mode 100644 index 000000000..6a41dcf34 --- /dev/null +++ b/ietf/meeting/migrations/0010_add_recorded_badness.py @@ -0,0 +1,347 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'ScheduledSession.badness' + db.add_column('meeting_scheduledsession', 'badness', + self.gf('django.db.models.fields.IntegerField')(default=0, null=True), + keep_default=False) + + # Adding field 'Schedule.badness' + db.add_column('meeting_schedule', 'badness', + self.gf('django.db.models.fields.IntegerField')(default=0, null=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'ScheduledSession.badness' + db.delete_column('meeting_scheduledsession', 'badness') + + # Deleting field 'Schedule.badness' + db.delete_column('meeting_schedule', 'badness') + + + 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': '64'}) + }, + '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'}) + }, + 'doc.docalias': { + 'Meta': {'object_name': 'DocAlias'}, + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}) + }, + 'doc.document': { + 'Meta': {'object_name': 'Document'}, + 'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}), + 'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}), + 'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}), + 'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}), + 'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'related': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'reversely_related_document_set'", 'blank': 'True', 'through': "orm['doc.RelatedDocument']", 'to': "orm['doc.DocAlias']"}), + 'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}), + 'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}), + 'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}) + }, + 'doc.documentauthor': { + 'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'doc.relateddocument': { + 'Meta': {'object_name': 'RelatedDocument'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}), + 'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}), + 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocAlias']"}) + }, + 'doc.state': { + 'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': "orm['doc.State']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'doc.statetype': { + 'Meta': {'object_name': 'StateType'}, + 'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'}) + }, + 'group.group': { + 'Meta': {'object_name': 'Group'}, + 'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), + 'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}), + 'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'meeting.constraint': { + 'Meta': {'object_name': 'Constraint'}, + 'day': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.ConstraintName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'constraint_source_set'", 'to': "orm['group.Group']"}), + 'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'constraint_target_set'", 'null': 'True', 'to': "orm['group.Group']"}) + }, + 'meeting.meeting': { + 'Meta': {'object_name': 'Meeting'}, + 'agenda': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['meeting.Schedule']"}), + 'agenda_note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'break_area': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}), + 'date': ('django.db.models.fields.DateField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'number': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}), + 'reg_area': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'time_zone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.MeetingTypeName']"}), + 'venue_addr': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'venue_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}) + }, + 'meeting.room': { + 'Meta': {'object_name': 'Room'}, + 'capacity': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'meeting.schedule': { + 'Meta': {'object_name': 'Schedule'}, + 'badness': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']", 'null': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'meeting.scheduledsession': { + 'Meta': {'object_name': 'ScheduledSession'}, + 'badness': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Schedule']"}), + 'session': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['meeting.Session']", 'null': 'True'}), + 'timeslot': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.TimeSlot']"}) + }, + 'meeting.session': { + 'Meta': {'object_name': 'Session'}, + 'agenda_note': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'attendees': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'materials': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'requested': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'requested_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'requested_duration': ('ietf.meeting.timedeltafield.TimedeltaField', [], {'default': '0'}), + 'scheduled': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), + 'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.SessionStatusName']"}) + }, + 'meeting.timeslot': { + 'Meta': {'object_name': 'TimeSlot'}, + 'duration': ('ietf.meeting.timedeltafield.TimedeltaField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Room']", 'null': 'True', 'blank': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'sessions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'slots'", 'to': "orm['meeting.Session']", 'through': "orm['meeting.ScheduledSession']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True'}), + 'show_location': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.TimeSlotTypeName']"}) + }, + 'name.constraintname': { + 'Meta': {'ordering': "['order']", 'object_name': 'ConstraintName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.docrelationshipname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctagname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.groupstatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.grouptypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.intendedstdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.meetingtypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'MeetingTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.sessionstatusname': { + 'Meta': {'ordering': "['order']", 'object_name': 'SessionStatusName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.stdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.streamname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StreamName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.timeslottypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'TimeSlotTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'person.email': { + 'Meta': {'object_name': 'Email'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + 'person.person': { + 'Meta': {'object_name': 'Person'}, + 'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}), + 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['meeting'] diff --git a/ietf/meeting/migrations/0011_bepresent.py b/ietf/meeting/migrations/0011_bepresent.py new file mode 100644 index 000000000..8c02ca824 --- /dev/null +++ b/ietf/meeting/migrations/0011_bepresent.py @@ -0,0 +1,352 @@ +# -*- coding: utf-8 -*- +import datetime +import sys +from south.db import db +from south.v2 import DataMigration +from django.db import models +from ietf.meeting.models import Meeting + +def make_essential_person(session, person): + nc = session.people_constraints.create(person = person, + meeting = session.meeting, + name_id = 'bethere', + source = session.group) + nc.save() + #sys.stdout.write("created constraints for %s" % (person)) + return nc + +def add_bepresent_for_meeting(mtg): + # cribbed from ietf.secr.sreq.views make_bepresent_formset. + for session in mtg.session_set.all(): + if session.group is None: + continue + group = session.group + sys.stdout.write (" be there for wg:%s \n" % (session.group)) + dict_of_essential_people = {} + # see what people might already be listed. + for x in session.people_constraints.all(): + #print "add db: %u %s" % (x.person.pk, x.person) + dict_of_essential_people[x.person.pk] = x + # now, add the co-chairs if they were not already present + chairs = group.role_set.filter(name='chair') + for chairrole in chairs: + chair = chairrole.person + if not chair.pk in dict_of_essential_people: + #print "add chair: %u" % (chair.pk) + dict_of_essential_people[chair.pk] = make_essential_person(session, chair) + # add the responsible AD + if group.ad is not None: + if not group.ad.pk in dict_of_essential_people: + #print "add ad: %u" % (chair.pk) + dict_of_essential_people[group.ad.pk] = make_essential_person(session, group.ad) + #we are done + + +class Migration(DataMigration): + + def forwards(self, orm): + for mtg in Meeting.objects.all(): + sys.stdout.write ("Adding bethere constraints for meeting %s..\n" % (mtg.number)) + add_bepresent_for_meeting(mtg) + # + # + + def backwards(self, orm): + pass + + 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': '64'}) + }, + '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'}) + }, + 'doc.document': { + 'Meta': {'object_name': 'Document'}, + 'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}), + 'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}), + 'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}), + 'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}), + 'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}), + 'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}), + 'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}) + }, + 'doc.documentauthor': { + 'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'doc.state': { + 'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': "orm['doc.State']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'doc.statetype': { + 'Meta': {'object_name': 'StateType'}, + 'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'}) + }, + 'group.group': { + 'Meta': {'object_name': 'Group'}, + 'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), + 'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}), + 'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'meeting.constraint': { + 'Meta': {'object_name': 'Constraint'}, + 'day': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.ConstraintName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'constraint_source_set'", 'to': "orm['group.Group']"}), + 'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'constraint_target_set'", 'null': 'True', 'to': "orm['group.Group']"}) + }, + 'meeting.meeting': { + 'Meta': {'object_name': 'Meeting'}, + 'agenda': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['meeting.Schedule']"}), + 'agenda_note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'break_area': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}), + 'date': ('django.db.models.fields.DateField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'number': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}), + 'reg_area': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'time_zone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.MeetingTypeName']"}), + 'venue_addr': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'venue_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}) + }, + 'meeting.room': { + 'Meta': {'object_name': 'Room'}, + 'capacity': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'meeting.schedule': { + 'Meta': {'object_name': 'Schedule'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']", 'null': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'meeting.scheduledsession': { + 'Meta': {'object_name': 'ScheduledSession'}, + 'extendedfrom': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['meeting.ScheduledSession']", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Schedule']"}), + 'session': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['meeting.Session']", 'null': 'True'}), + 'timeslot': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.TimeSlot']"}) + }, + 'meeting.session': { + 'Meta': {'object_name': 'Session'}, + 'agenda_note': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'attendees': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'materials': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'requested': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'requested_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'requested_duration': ('ietf.meeting.timedeltafield.TimedeltaField', [], {'default': '0'}), + 'scheduled': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), + 'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.SessionStatusName']"}) + }, + 'meeting.timeslot': { + 'Meta': {'object_name': 'TimeSlot'}, + 'duration': ('ietf.meeting.timedeltafield.TimedeltaField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Room']", 'null': 'True', 'blank': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'sessions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'slots'", 'to': "orm['meeting.Session']", 'through': "orm['meeting.ScheduledSession']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True'}), + 'show_location': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.TimeSlotTypeName']"}) + }, + 'name.constraintname': { + 'Meta': {'ordering': "['order']", 'object_name': 'ConstraintName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctagname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.groupstatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.grouptypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.intendedstdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.meetingtypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'MeetingTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.sessionstatusname': { + 'Meta': {'ordering': "['order']", 'object_name': 'SessionStatusName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.stdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.streamname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StreamName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.timeslottypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'TimeSlotTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'person.email': { + 'Meta': {'object_name': 'Email'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + 'person.person': { + 'Meta': {'object_name': 'Person'}, + 'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}), + 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['meeting'] + symmetrical = True diff --git a/ietf/meeting/migrations/0012_auto__add_field_scheduledsession_pinned.py b/ietf/meeting/migrations/0012_auto__add_field_scheduledsession_pinned.py new file mode 100644 index 000000000..04f03b8d6 --- /dev/null +++ b/ietf/meeting/migrations/0012_auto__add_field_scheduledsession_pinned.py @@ -0,0 +1,317 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'ScheduledSession.pinned' + db.add_column('meeting_scheduledsession', 'pinned', + self.gf('django.db.models.fields.BooleanField')(default=False), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'ScheduledSession.pinned' + db.delete_column('meeting_scheduledsession', 'pinned') + + + 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': '64'}) + }, + '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'}) + }, + 'doc.document': { + 'Meta': {'object_name': 'Document'}, + 'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}), + 'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}), + 'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}), + 'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}), + 'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}), + 'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}), + 'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}) + }, + 'doc.documentauthor': { + 'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'doc.state': { + 'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': "orm['doc.State']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'doc.statetype': { + 'Meta': {'object_name': 'StateType'}, + 'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'}) + }, + 'group.group': { + 'Meta': {'object_name': 'Group'}, + 'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), + 'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}), + 'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'meeting.constraint': { + 'Meta': {'object_name': 'Constraint'}, + 'day': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.ConstraintName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'constraint_source_set'", 'to': "orm['group.Group']"}), + 'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'constraint_target_set'", 'null': 'True', 'to': "orm['group.Group']"}) + }, + 'meeting.meeting': { + 'Meta': {'object_name': 'Meeting'}, + 'agenda': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['meeting.Schedule']"}), + 'agenda_note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'break_area': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}), + 'date': ('django.db.models.fields.DateField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'number': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}), + 'reg_area': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'time_zone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.MeetingTypeName']"}), + 'venue_addr': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'venue_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}) + }, + 'meeting.room': { + 'Meta': {'object_name': 'Room'}, + 'capacity': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'meeting.schedule': { + 'Meta': {'object_name': 'Schedule'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']", 'null': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'meeting.scheduledsession': { + 'Meta': {'object_name': 'ScheduledSession'}, + 'extendedfrom': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['meeting.ScheduledSession']", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'pinned': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Schedule']"}), + 'session': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['meeting.Session']", 'null': 'True'}), + 'timeslot': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.TimeSlot']"}) + }, + 'meeting.session': { + 'Meta': {'object_name': 'Session'}, + 'agenda_note': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'attendees': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'materials': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'requested': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'requested_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}), + 'requested_duration': ('ietf.meeting.timedeltafield.TimedeltaField', [], {'default': '0'}), + 'scheduled': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}), + 'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.SessionStatusName']"}) + }, + 'meeting.timeslot': { + 'Meta': {'object_name': 'TimeSlot'}, + 'duration': ('ietf.meeting.timedeltafield.TimedeltaField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Room']", 'null': 'True', 'blank': 'True'}), + 'meeting': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['meeting.Meeting']"}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'sessions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'slots'", 'to': "orm['meeting.Session']", 'through': "orm['meeting.ScheduledSession']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True'}), + 'show_location': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.TimeSlotTypeName']"}) + }, + 'name.constraintname': { + 'Meta': {'ordering': "['order']", 'object_name': 'ConstraintName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctagname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.groupstatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.grouptypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.intendedstdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.meetingtypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'MeetingTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.sessionstatusname': { + 'Meta': {'ordering': "['order']", 'object_name': 'SessionStatusName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.stdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.streamname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StreamName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.timeslottypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'TimeSlotTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'person.email': { + 'Meta': {'object_name': 'Email'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + 'person.person': { + 'Meta': {'object_name': 'Person'}, + 'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}), + 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['meeting'] \ No newline at end of file diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py index 973e72917..34cd85a88 100644 --- a/ietf/meeting/models.py +++ b/ietf/meeting/models.py @@ -112,6 +112,15 @@ class Meeting(models.Model): return qs[0] return None + @property + def sessions_that_wont_meet(self): + return self.session_set.filter(status__slug='notmeet') + + @property + def sessions_that_can_meet(self): + return self.session_set.exclude(status__slug='notmeet').exclude(status__slug='disappr').exclude(status__slug='deleted').exclude(status__slug='apprw') + + def json_url(self): return "/meeting/%s.json" % (self.number, ) @@ -125,7 +134,7 @@ class Meeting(models.Model): if self.agenda: agenda_url = urljoin(host_scheme, self.agenda.base_url()) return { - 'href': urljoin(host_scheme, self.base_url()), + 'href': urljoin(host_scheme, self.json_url()), 'name': self.number, 'submission_start_date': fmt_date(self.get_submission_start_date()), 'submission_cut_off_date': fmt_date(self.get_submission_cut_off_date()), @@ -187,7 +196,7 @@ class Room(models.Model): capacity = models.IntegerField(null=True, blank=True) def __unicode__(self): - return self.name + return "%s size: %u" % (self.name, self.capacity) def delete_timeslots(self): for ts in self.timeslot_set.all(): @@ -363,7 +372,6 @@ class TimeSlot(models.Model): def json_url(self): return "/meeting/%s/timeslot/%s.json" % (self.meeting.number, self.id) - """ This routine takes the current timeslot, which is assumed to have no location, and assigns a room, and then creates an identical timeslot for all of the other @@ -378,6 +386,7 @@ class TimeSlot(models.Model): ts.id = None ts.location = room ts.save() + self.meeting.create_all_timeslots() """ @@ -428,6 +437,7 @@ class Schedule(models.Model): owner = models.ForeignKey(Person) visible = models.BooleanField(default=True, help_text=u"Make this agenda available to those who know about it") public = models.BooleanField(default=True, help_text=u"Make this agenda publically available") + badness = models.IntegerField(null=True, blank=True) # considering copiedFrom = models.ForeignKey('Schedule', blank=True, null=True) def __unicode__(self): @@ -436,8 +446,12 @@ class Schedule(models.Model): def base_url(self): return "/meeting/%s/agenda/%s" % (self.meeting.number, self.name) - def url_edit(self): - return "/meeting/%s/agenda/%s/edit" % (self.meeting.number, self.name) +# def url_edit(self): +# return "/meeting/%s/agenda/%s/edit" % (self.meeting.number, self.name) +# +# @property +# def relurl_edit(self): +# return self.url_edit("") @property def visible_token(self): @@ -464,6 +478,10 @@ class Schedule(models.Model): else: return "agenda_unofficial" + # returns a dictionary {group -> [scheduledsession+]} + # and it has [] if the session is not placed. + # if there is more than one session for that group, + # then a list of them is returned (always a list) @property def official_token(self): if self.is_official: @@ -496,6 +514,60 @@ class Schedule(models.Model): # should include href to list of scheduledsessions, but they have no direct API yet. return sch + @property + def qs_scheduledsessions_with_assignments(self): + return self.scheduledsession_set.filter(session__isnull=False) + + @property + def qs_scheduledsessions_without_assignments(self): + return self.scheduledsession_set.filter(session__isnull=True) + + @property + def group_mapping(self): + assignments,sessions,total,scheduled = self.group_session_mapping + return assignments + + @property + def group_session_mapping(self): + assignments = dict() + sessions = dict() + total = 0 + scheduled = 0 + allschedsessions = self.qs_scheduledsessions_with_assignments.filter(timeslot__type = "session").all() + for sess in self.meeting.sessions_that_can_meet.all(): + assignments[sess.group] = [] + sessions[sess] = None + total =+ 1 + + for ss in allschedsessions: + assignments[ss.session.group].append(ss) + # XXX can not deal with a session in two slots + sessions[ss.session] = ss + scheduled =+ 1 + return assignments,sessions,total,scheduled + + # calculate badness of entire schedule + def calc_badness(self): + # now calculate badness + assignments = self.group_mapping + return self.calc_badness1(assignments) + + cached_sessions_that_can_meet = None + @property + def sessions_that_can_meet(self): + if self.cached_sessions_that_can_meet is None: + self.cached_sessions_that_can_meet = self.meeting.sessions_that_can_meet.all() + return self.cached_sessions_that_can_meet + + # calculate badness of entire schedule + def calc_badness1(self, assignments): + badness = 0 + for sess in self.sessions_that_can_meet: + badness += sess.badness(assignments) + self.badness = badness + return badness + + class ScheduledSession(models.Model): """ This model provides an N:M relationship between Session and TimeSlot. @@ -508,6 +580,11 @@ class ScheduledSession(models.Model): extendedfrom = models.ForeignKey('ScheduledSession', null=True, default=None, help_text=u"Timeslot this session is an extension of") modified = models.DateTimeField(default=datetime.datetime.now) notes = models.TextField(blank=True) + badness = models.IntegerField(default=0, blank=True, null=True) + pinned = models.BooleanField(default=False, help_text="Do not move session during automatic placement") + + # use to distinguish this from FakeScheduledSession in placement.py + faked = "real" def __unicode__(self): return u"%s [%s<->%s]" % (self.schedule, self.session, self.timeslot) @@ -628,6 +705,7 @@ class ScheduledSession(models.Model): ss["time"] = date_format(self.timeslot.time, 'Hi') ss["date"] = time_format(self.timeslot.time, 'Y-m-d') ss["domid"] = self.timeslot.js_identifier + ss["pinned"] = self.pinned return ss @@ -636,7 +714,7 @@ class Constraint(models.Model): Specifies a constraint on the scheduling. One type (name=conflic?) of constraint is between source WG and target WG, e.g. some kind of conflict. - Another type (name=adpresent) of constraing is between source WG and + Another type (name=bethere) of constraing is between source WG and availability of a particular Person, usually an AD. A third type (name=avoidday) of constraing is between source WG and a particular day of the week, specified in day. @@ -648,8 +726,37 @@ class Constraint(models.Model): day = models.DateTimeField(null=True, blank=True) name = models.ForeignKey(ConstraintName) + active_status = None + def __unicode__(self): - return u"%s %s %s" % (self.source, self.name.name.lower(), self.target) + return u"%s %s target=%s person=%s" % (self.source, self.name.name.lower(), self.target, self.person) + + @property + def person_conflicted(self): + if self.person is None: + return "unknown person" + return self.person.name + + def status(self): + if self.active_status is not None: + return self.active_status + else: + return True + + def __lt__(self, y): + #import sys + #sys.stdout.write("me: %s y: %s\n" % (self.name.slug, y.name.slug)) + if self.name.slug == 'conflict' and y.name.slug == 'conflic2': + return True + if self.name.slug == 'conflict' and y.name.slug == 'conflic3': + return True + if self.name.slug == 'conflic2' and y.name.slug == 'conflic3': + return True + return False + + @property + def constraint_cost(self): + return self.name.cost(); def json_url(self): return "/meeting/%s/constraint/%s.json" % (self.meeting.number, self.id) @@ -668,7 +775,8 @@ class Constraint(models.Model): ct1['meeting_href'] = urljoin(host_scheme, self.meeting.json_url()) return ct1 - +constraint_cache_uses = 0 +constraint_cache_initials = 0 class Session(models.Model): """Session records that a group should have a session on the @@ -692,6 +800,8 @@ class Session(models.Model): materials = models.ManyToManyField(Document, blank=True) + unique_constraints_dict = None + def agenda(self): items = self.materials.filter(type="agenda",states__type="agenda",states__slug="active") if items and items[0] is not None: @@ -719,7 +829,7 @@ class Session(models.Model): ss = self.scheduledsession_set.order_by('timeslot__time') if ss: ss0name = ss[0].timeslot.time.strftime("%H%M") - return u"%s: %s %s" % (self.meeting, self.group.acronym, ss0name) + return u"%s: %s %s[%u]" % (self.meeting, self.group.acronym, ss0name, self.pk) @property def short_name(self): @@ -750,38 +860,269 @@ class Session(models.Model): def official_scheduledsession(self): return self.scheduledsession_for_agenda(self.meeting.agenda) + def unique_constraints(self): + global constraint_cache_uses, constraint_cache_initials + constraint_cache_uses += 1 + # this cache keeps the automatic placer from visiting the database continuously + if self.unique_constraints_dict is not None: + constraint_cache_initials += 1 + return self.unique_constraints_dict + self.unique_constraints_dict = dict() + for constraint in self.constraints(): + self.unique_constraints_dict[constraint.target] = constraint + + for constraint in self.reverse_constraints(): + # update the constraint if there is a previous one, and + # it is more important than what we had before + if not (constraint in self.unique_constraints_dict) or (self.unique_constraints_dict[constraint.source] < constraint): + self.unique_constraints_dict[constraint.source] = constraint + return self.unique_constraints_dict + def constraints_dict(self, host_scheme): constraint_list = [] - for constraint in self.group.constraint_source_set.filter(meeting=self.meeting): + for constraint in self.constraints(): ct1 = constraint.json_dict(host_scheme) constraint_list.append(ct1) - for constraint in self.group.constraint_target_set.filter(meeting=self.meeting): + for constraint in self.reverse_constraints(): ct1 = constraint.json_dict(host_scheme) constraint_list.append(ct1) return constraint_list + @property + def people_constraints(self): + return self.group.constraint_source_set.filter(meeting=self.meeting, name='bethere') + def json_url(self): return "/meeting/%s/session/%s.json" % (self.meeting.number, self.id) def json_dict(self, host_scheme): sess1 = dict() sess1['href'] = urljoin(host_scheme, self.json_url()) - sess1['group_href'] = urljoin(host_scheme, self.group.json_url()) - sess1['group_acronym'] = str(self.group.acronym) + if self.group is not None: + sess1['group'] = self.group.json_dict(host_scheme) + # nuke rest of these as soon as JS cleaned up. + sess1['group_href'] = urljoin(host_scheme, self.group.json_url()) + sess1['group_acronym'] = str(self.group.acronym) + if self.group.parent is not None: + sess1['area'] = str(self.group.parent.acronym).upper() + sess1['GroupInfo_state']= str(self.group.state) + sess1['description'] = str(self.group.name) + sess1['group_id'] = str(self.group.pk) + sess1['session_id'] = str(self.pk) sess1['name'] = str(self.name) - sess1['short_name'] = str(self.name) + sess1['title'] = str(self.short_name) + sess1['short_name'] = str(self.short_name) sess1['agenda_note'] = str(self.agenda_note) sess1['attendees'] = str(self.attendees) sess1['status'] = str(self.status) if self.comments is not None: sess1['comments'] = str(self.comments) sess1['requested_time'] = str(self.requested.strftime("%Y-%m-%d")) - sess1['requested_by'] = str(self.requested_by) - sess1['requested_duration']= "%.1f h" % (float(self.requested_duration.seconds) / 3600) - sess1['area'] = str(self.group.parent.acronym) - sess1['responsible_ad'] = str(self.group.ad) - sess1['GroupInfo_state']= str(self.group.state) + # the related person object sometimes does not exist in the dataset. + try: + if self.requested_by is not None: + sess1['requested_by'] = str(self.requested_by) + except Person.DoesNotExist: + pass + + sess1['requested_duration']= "%.1f" % (float(self.requested_duration.seconds) / 3600) + sess1['duration'] = sess1['requested_duration'] + sess1['special_request'] = str(self.special_request_token) return sess1 + def badness_test(self, num): + import sys + from settings import BADNESS_CALC_LOG + #sys.stdout.write("num: %u / BAD: %u\n" % (num, BADNESS_CALC_LOG)) + return BADNESS_CALC_LOG >= num + + def badness_log(self, num, msg): + if self.badness_test(num): + sys.stdout.write(msg) + + # this evaluates the current session based upon the constraints + # given, in the context of the assignments in the array. + # + # MATH. + # each failed conflic3 is worth 1000 points + # each failed conflic2 is worth 10000 points + # each failed conflic1 is worth 100000 points + # being in a room too small than asked is worth 200,000 * (size/50) + # being in a room too big by more than 100 is worth 200,000 once. + # a conflict where AD must be in two places is worth 500,000. + # not being scheduled is worth 10,000,000 points + # + def badness(self, assignments): + badness = 0 + + if not (self.group in assignments): + return 0 + + conflicts = self.unique_constraints() + + if self.badness_test(2): + self.badness_log(2, "badgroup: %s badness calculation has %u constraints\n" % (self.group.acronym, len(conflicts))) + import sys + from settings import BADNESS_UNPLACED, BADNESS_TOOSMALL_50, BADNESS_TOOSMALL_100, BADNESS_TOOBIG, BADNESS_MUCHTOOBIG + count = 0 + myss_list = assignments[self.group] + # for each constraint of this sessions' group, by group + if len(myss_list)==0: + if self.badness_test(2): + self.badness_log(2, " 0group: %s is unplaced\n" % (self.group.acronym)) + return BADNESS_UNPLACED + + for myss in myss_list: + if self.attendees is None or myss.timeslot is None or myss.timeslot.location.capacity is None: + continue + mismatch = self.attendees - myss.timeslot.location.capacity + if mismatch > 100: + # the room is too small by 100 + badness += BADNESS_TOOSMALL_100 + elif mismatch > 50: + # the room is too small by 50 + badness += BADNESS_TOOSMALL_50 + elif mismatch < 50: + # the room is too big by 50 + badness += BADNESS_TOOBIG + elif mismatch < 100: + # the room is too big by 100 (not intimate enough) + badness += BADNESS_MUCHTOOBIG + + for group,constraint in conflicts.items(): + if group is None: + # must not be a group constraint. + continue + count += 1 + # get the list of sessions for other group. + sess_count = 0 + if group in assignments: + sess_count = len(assignments[group]) + if self.badness_test(4): + self.badness_log(4, " [%u] 1group: %s session_count: %u\n" % (count, group.acronym, sess_count)) + + # see if the other group which is conflicted, has an assignment, + if group in assignments: + other_sessions = assignments[group] + # and if it does, see if any of it's sessions conflict with any of my sessions + # (each group could have multiple slots) + #if self.badness_test(4): + # self.badness_log(4, " [%u] 9group: other sessions: %s\n" % (count, other_sessions)) + for ss in other_sessions: + # this causes additional database dips + #if self.badness_test(4): + # self.badness_log(4, " [%u] 9group: ss: %s %s\n" % (count, ss, ss.faked)) + if ss.session is None: + continue + if ss.timeslot is None: + continue + if self.badness_test(3): + self.badness_log(3, " [%u] 2group: %s vs ogroup: %s\n" % (count, self.group.acronym, ss.session.group.acronym)) + if ss.session.group.acronym == self.group.acronym: + continue + if self.badness_test(3): + self.badness_log(3, " [%u] 3group: %s sessions: %s\n" % (count, group.acronym, ss.timeslot.time)) + # see if they are scheduled at the same time. + conflictbadness = 0 + for myss in myss_list: + if myss.timeslot is None: + continue + if self.badness_test(3): + self.badness_log(3, " [%u] 4group: %s my_sessions: %s vs %s\n" % (count, group.acronym, myss.timeslot.time, ss.timeslot.time)) + if ss.timeslot.time == myss.timeslot.time: + newcost = constraint.constraint_cost + if self.badness_test(2): + self.badness_log(2, " [%u] 5group: %s conflicts: %s on %s cost %u\n" % (count, self.group.acronym, ss.session.group.acronym, ss.timeslot.time, newcost)) + # yes accumulate badness. + conflictbadness += newcost + ss.badness = conflictbadness + ss.save() + badness += conflictbadness + # done + if self.badness_test(1): + self.badness_log(1, "badgroup: %s badness = %u\n" % (self.group.acronym, badness)) + return badness + + def setup_conflicts(self): + conflicts = self.unique_constraints() + + self.session_conflicts = [] + + for group,constraint in conflicts.items(): + if group is None: + # must not be a group constraint, people constraints TBD. + continue + + # get the list of sessions for other group. + for session in self.meeting.session_set.filter(group = group): + # make a tuple... + conflict = (session.pk, constraint) + self.session_conflicts.append(conflict) + + # This evaluates the current session based upon the constraints + # given. The conflicts have first been shorted into an array (session_conflicts) + # as a tuple, and include the constraint itself. + # + # While the conflicts are listed by group, the conflicts listed here + # have been resolved into pk of session requests that will conflict. + # This is to make comparison be a straight integer comparison. + # + # scheduleslot contains the list of sessions which are at the same time as + # this item. + # + # timeslot is where this item has been scheduled. + # + # MATH. + # each failed conflic3 is worth 1000 points + # each failed conflic2 is worth 10000 points + # each failed conflic1 is worth 100000 points + # being in a room too small than asked is worth 200,000 * (size/50) + # being in a room too big by more than 100 is worth 200,000 once. + # a conflict where AD must be in two places is worth 500,000. + # not being scheduled is worth 10,000,000 points + # + def badness_fast(self, timeslot, scheduleslot, session_pk_list): + from settings import BADNESS_UNPLACED, BADNESS_TOOSMALL_50, BADNESS_TOOSMALL_100, BADNESS_TOOBIG, BADNESS_MUCHTOOBIG + + badness = 0 + + # see if item has not been scheduled + if timeslot is None: + return BADNESS_UNPLACED + + # see if this session is in too small a place. + if self.attendees is not None and timeslot.location.capacity is not None: + mismatch = self.attendees - timeslot.location.capacity + if mismatch > 100: + # the room is too small by 100 + badness += BADNESS_TOOSMALL_100 + elif mismatch > 50: + # the room is too small by 50 + badness += BADNESS_TOOSMALL_50 + elif mismatch < 50: + # the room is too big by 50 + badness += BADNESS_TOOBIG + elif mismatch < 100: + # the room is too big by 100 (not intimate enough) + badness += BADNESS_MUCHTOOBIG + + # now go through scheduleslot items and see if any are conflicts + # inner loop is the shorter one, usually max 8 rooms. + for conflict in self.session_conflicts: + for pkt in session_pk_list: + pk = pkt[0] + if pk == self.pk: # ignore conflicts with self. + continue + + if conflict[0] == pk: + ss = pkt[1] + if ss.timeslot is not None and ss.timeslot.location == timeslot.location: + continue # ignore conflicts when two sessions in the same room + constraint = conflict[1] + badness += constraint.constraint_cost + + if self.badness_test(1): + self.badness_log(1, "badgroup: %s badness = %u\n" % (self.group.acronym, badness)) + return badness diff --git a/ietf/meeting/tests/agenda-83-txt-output.txt b/ietf/meeting/tests/agenda-83-txt-output.txt index a3843071a..e4de97eb2 100644 --- a/ietf/meeting/tests/agenda-83-txt-output.txt +++ b/ietf/meeting/tests/agenda-83-txt-output.txt @@ -226,5 +226,6 @@ AREA DIRECTORS APP Applications Area Barry Leiba/Huawei Technologies & Pete Resnick/QTI, a Qualcomm company GEN General Area Russ Housley/Vigil Security, LLC OPS Operations and Man Ron Bonica/Juniper Networks & Benoit Claise/Cisco +RAI Real-time Applicat Gonzalo Camarillo/Ericsson SEC Security Area Stephen Farrell/Trinity College Dublin & Sean Turner/IECA diff --git a/ietf/meeting/tests/agenda-83-utc-output.html b/ietf/meeting/tests/agenda-83-utc-output.html index abc188015..ff5c81f29 100644 --- a/ietf/meeting/tests/agenda-83-utc-output.html +++ b/ietf/meeting/tests/agenda-83-utc-output.html @@ -90,7 +90,7 @@ img.hidden { display: none; } - + - - - + + + + {% endblock pagehead %} diff --git a/ietf/templates/meeting/landscape_edit.html b/ietf/templates/meeting/landscape_edit.html index 48fc6d342..7f20a56b5 100644 --- a/ietf/templates/meeting/landscape_edit.html +++ b/ietf/templates/meeting/landscape_edit.html @@ -9,6 +9,11 @@ {% block morecss %} {% for area in area_list %} .{{ area.upcase_acronym}}-scheme, .meeting_event th.{{ area.upcase_acronym}}-scheme, #{{ area.upcase_acronym }}-groups, #selector-{{ area.upcase_acronym }} { color:{{ area.fg_color }}; background-color: {{ area.bg_color }} } +.director-mark-{{ area.upcase_acronym}} { + border: 2px solid {{ area.fg_color}}; + color:{{ area.fg_color }}; + background-color: {{ area.bg_color }} +} {% endfor %} {% endblock morecss %} @@ -29,24 +34,13 @@ -{% if server_mode %} - {% ifnotequal server_mode "production" %} - - {% endifnotequal %} -{% endif %} - - - - - - {% dajaxice_js_import %} - - - - + + + + - - - + + + + {% endblock pagehead %} diff --git a/ietf/templates/meeting/timeslot_edit.html b/ietf/templates/meeting/timeslot_edit.html index 99e83bb30..34887b57b 100644 --- a/ietf/templates/meeting/timeslot_edit.html +++ b/ietf/templates/meeting/timeslot_edit.html @@ -28,11 +28,11 @@ {% dajaxice_js_import %} - - - - - + + + + +