From 89ac692442bc1ebcbddc8b35bd576e4ef6611b7e Mon Sep 17 00:00:00 2001
From: Henrik Levkowetz <henrik@levkowetz.com>
Date: Wed, 27 Jun 2012 08:26:18 +0000
Subject: [PATCH] Added in the community app, which wasn't included properly in
 the previous commit.  - Legacy-Id: 4519

---
 ietf/community/__init__.py                    |   0
 ietf/community/constants.py                   |  23 ++
 ietf/community/display.py                     | 173 +++++++++
 ietf/community/forms.py                       | 101 ++++++
 ietf/community/management/__init__.py         |   0
 .../community/management/commands/__init__.py |   0
 .../commands/update_community_lists.py        |  36 ++
 .../commands/update_doc_change_dates.py       |  39 +++
 .../migrations/0001_initial_migration.py      | 257 ++++++++++++++
 .../migrations/0002_add_display_config.py     | 231 ++++++++++++
 .../migrations/0003_add_notifications.py      | 295 ++++++++++++++++
 ...04_refactor_notifications_with_docevent.py | 262 ++++++++++++++
 ...05_auto__add_field_communitylist_secret.py | 245 +++++++++++++
 ...06_auto__add_field_communitylist_cached.py | 246 +++++++++++++
 ietf/community/migrations/__init__.py         |   0
 ietf/community/models.py                      | 262 ++++++++++++++
 ietf/community/rules.py                       | 139 ++++++++
 ietf/community/templatetags/__init__.py       |   0
 ietf/community/templatetags/community_tags.py |  80 +++++
 ietf/community/urls.py                        |  32 ++
 ietf/community/utils.py                       |  43 +++
 ietf/community/views.py                       | 329 ++++++++++++++++++
 ietf/settings.py                              |  14 +-
 23 files changed, 2800 insertions(+), 7 deletions(-)
 create mode 100644 ietf/community/__init__.py
 create mode 100644 ietf/community/constants.py
 create mode 100644 ietf/community/display.py
 create mode 100644 ietf/community/forms.py
 create mode 100644 ietf/community/management/__init__.py
 create mode 100644 ietf/community/management/commands/__init__.py
 create mode 100644 ietf/community/management/commands/update_community_lists.py
 create mode 100644 ietf/community/management/commands/update_doc_change_dates.py
 create mode 100644 ietf/community/migrations/0001_initial_migration.py
 create mode 100644 ietf/community/migrations/0002_add_display_config.py
 create mode 100644 ietf/community/migrations/0003_add_notifications.py
 create mode 100644 ietf/community/migrations/0004_refactor_notifications_with_docevent.py
 create mode 100644 ietf/community/migrations/0005_auto__add_field_communitylist_secret.py
 create mode 100644 ietf/community/migrations/0006_auto__add_field_communitylist_cached.py
 create mode 100644 ietf/community/migrations/__init__.py
 create mode 100644 ietf/community/models.py
 create mode 100644 ietf/community/rules.py
 create mode 100644 ietf/community/templatetags/__init__.py
 create mode 100644 ietf/community/templatetags/community_tags.py
 create mode 100644 ietf/community/urls.py
 create mode 100644 ietf/community/utils.py
 create mode 100644 ietf/community/views.py

diff --git a/ietf/community/__init__.py b/ietf/community/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/ietf/community/constants.py b/ietf/community/constants.py
new file mode 100644
index 000000000..9bcad3fb5
--- /dev/null
+++ b/ietf/community/constants.py
@@ -0,0 +1,23 @@
+SIGNIFICANT_STATES = [
+    'Adopted by a WG',
+    'In WG Last Call',
+    'WG Consensus: Waiting for Write-Up',
+    'Parked WG Document',
+    'Dead WG Document',
+    'Active IAB Document',
+    'Community Review',
+    'Sent to the RFC Editor',
+    'Active RG Document',
+    'In RG Last Call',
+    'Awaiting IRSG Reviews',
+    'In IESG Review',
+    'Document on Hold Based On IESG Request',
+    'Submission Received',
+    'In ISE Review',
+    'In IESG Review',
+    'RFC Published',
+    'Dead',
+    'IESG Evaluation',
+    'Publication Requested',
+    'In Last Call',
+]
diff --git a/ietf/community/display.py b/ietf/community/display.py
new file mode 100644
index 000000000..a84a8c306
--- /dev/null
+++ b/ietf/community/display.py
@@ -0,0 +1,173 @@
+import datetime
+
+from django.db.models import Q
+from ietf.ietfworkflows.utils import get_state_for_draft
+
+from redesign.doc.models import DocAlias, DocEvent
+
+
+class DisplayField(object):
+
+    codename = ''
+    description = ''
+
+    def get_value(self, document, raw=False):
+        return None
+
+
+class FilenameField(DisplayField):
+    codename = 'filename'
+    description = 'I-D filename'
+
+    def get_value(self, document, raw=False):
+        if not raw:
+            return '<a href="%s">%s</a>' % (document.get_absolute_url(), document.canonical_name())
+        else:
+            return document.canonical_name()
+
+
+class TitleField(DisplayField):
+    codename = 'title'
+    description = 'I-D title'
+
+    def get_value(self, document, raw=False):
+        return document.title
+
+
+class DateField(DisplayField):
+    codename = 'date'
+    description = 'Date of current I-D'
+
+    def get_value(self, document, raw=False):
+        date = document.latest_event(type='new_revision')
+        if date:
+            return date.time.strftime('%Y-%m-%d')
+        return document.time.strftime('%Y-%m-%d')
+
+
+class StatusField(DisplayField):
+    codename = 'status'
+    description = 'Status in the IETF process'
+
+    def get_value(self, document, raw=False):
+        for i in ('draft', 'draft-stream-ietf', 'draft-stream-irtf', 'draft-stream-ise', 'draft-stream-iab', 'draft'):
+            state = document.get_state(i)
+            if state:
+                return state
+        return ''
+
+
+class WGField(DisplayField):
+    codename = 'wg_rg'
+    description = 'Associated WG or RG'
+
+    def get_value(self, document, raw=False):
+        return document.group or ''
+
+
+class ADField(DisplayField):
+    codename = 'ad'
+    description = 'Associated AD, if any'
+
+    def get_value(self, document, raw=False):
+        return document.ad or ''
+
+
+class OneDayField(DisplayField):
+    codename = '1_day'
+    description = 'Changed within the last 1 day'
+
+    def get_value(self, document, raw=False):
+        now = datetime.datetime.now()
+        last = now - datetime.timedelta(days=1)
+        if document.docevent_set.filter(time__gte=last):
+            return raw and 'YES' or '&#10004;'
+        return ''
+
+
+class TwoDaysField(DisplayField):
+    codename = '2_days'
+    description = 'Changed within the last 2 days'
+
+    def get_value(self, document, raw=False):
+        now = datetime.datetime.now()
+        last = now - datetime.timedelta(days=2)
+        if document.docevent_set.filter(time__gte=last):
+            return raw and 'YES' or '&#10004;'
+        return ''
+
+
+class SevenDaysField(DisplayField):
+    codename = '7_days'
+    description = 'Changed within the last 7 days'
+
+    def get_value(self, document, raw=False):
+        now = datetime.datetime.now()
+        last = now - datetime.timedelta(days=7)
+        if document.docevent_set.filter(time__gte=last):
+            return raw and 'YES' or '&#10004;'
+        return ''
+
+
+TYPES_OF_DISPLAY_FIELDS = [(i.codename, i.description) for i in DisplayField.__subclasses__()]
+
+
+class SortMethod(object):
+    codename = ''
+    description = ''
+
+    def get_sort_field(self):
+        return 'pk'
+
+
+class FilenameSort(SortMethod):
+    codename = 'by_filename'
+    description = 'Alphabetical by I-D filename and RFC number'
+
+    def get_sort_field(self):
+        return 'name'
+
+    def get_full_rfc_sort(self, documents):
+        return [i.document for i in DocAlias.objects.filter(document__in=documents, name__startswith='rfc').order_by('name')]
+
+
+class TitleSort(SortMethod):
+    codename = 'by_title'
+    description = 'Alphabetical by document title'
+
+    def get_sort_field(self):
+        return 'title'
+
+
+class WGSort(SortMethod):
+    codename = 'by_wg'
+    description = 'Alphabetical by associated WG'
+
+    def get_sort_field(self):
+        return 'group__name'
+
+
+class PublicationSort(SortMethod):
+    codename = 'date_publication'
+    description = 'Date of publication of current version of the document'
+
+    def get_sort_field(self):
+        return '-documentchangedates__new_version_date'
+
+class ChangeSort(SortMethod):
+    codename = 'recent_change'
+    description = 'Date of most recent change of status of any type'
+
+    def get_sort_field(self):
+        return '-documentchangedates__normal_change_date'
+
+
+class SignificantSort(SortMethod):
+    codename = 'recent_significant'
+    description = 'Date of most recent significant change of status'
+
+    def get_sort_field(self):
+        return '-documentchangedates__significant_change_date'
+
+
+TYPES_OF_SORT = [(i.codename, i.description) for i in SortMethod.__subclasses__()]
diff --git a/ietf/community/forms.py b/ietf/community/forms.py
new file mode 100644
index 000000000..63d5b9bf6
--- /dev/null
+++ b/ietf/community/forms.py
@@ -0,0 +1,101 @@
+import hashlib
+import datetime
+
+from django import forms
+from django.conf import settings
+from django.contrib.sites.models import Site
+
+from ietf.utils.mail import send_mail
+from ietf.community.models import Rule, DisplayConfiguration, RuleManager
+from ietf.community.display import DisplayField
+
+
+class RuleForm(forms.ModelForm):
+
+    class Meta:
+        model = Rule
+        fields = ('rule_type', 'value')
+
+    def __init__(self, *args, **kwargs):
+        self.clist = kwargs.pop('clist', None)
+        super(RuleForm, self).__init__(*args, **kwargs)
+
+    def save(self):
+        self.instance.community_list = self.clist
+        super(RuleForm, self).save()
+
+    def get_all_options(self):
+        result = []
+        for i in RuleManager.__subclasses__():
+            options = i(None).options()
+            if options:
+                result.append({'type': i.codename,
+                               'options': options})
+        return result
+        
+
+class DisplayForm(forms.ModelForm):
+
+    class Meta:
+        model = DisplayConfiguration
+        fields = ('sort_method', )
+
+    def save(self):
+        data = self.data
+        fields = []
+        for i in DisplayField.__subclasses__():
+            if data.get(i.codename, None):
+                fields.append(i.codename)
+        self.instance.display_fields = ','.join(fields)
+        super(DisplayForm, self).save()
+
+
+class SubscribeForm(forms.Form):
+
+    email = forms.EmailField("Your email")
+
+    def __init__(self, *args, **kwargs):
+        self.clist = kwargs.pop('clist')
+        self.significant = kwargs.pop('significant')
+        super(SubscribeForm, self).__init__(*args, **kwargs)
+
+    def save(self, *args, **kwargs):
+        self.send_email()
+        return True
+
+    def send_email(self):
+        domain = Site.objects.get_current().domain
+        today = datetime.date.today().strftime('%Y%m%d')
+        subject = 'Confirm list subscription: %s' % self.clist
+        from_email = settings.DEFAULT_FROM_EMAIL
+        to_email = self.cleaned_data['email']
+        auth = hashlib.md5('%s%s%s%s%s' % (settings.SECRET_KEY, today, to_email, 'subscribe', self.significant)).hexdigest()
+        context = {
+            'domain': domain,
+            'clist': self.clist,
+            'today': today,
+            'auth': auth,
+            'to_email': to_email,
+            'significant': self.significant,
+        }
+        send_mail(None, to_email, from_email, subject, 'community/public/subscribe_email.txt', context)
+
+
+class UnSubscribeForm(SubscribeForm):
+
+    def send_email(self):
+        domain = Site.objects.get_current().domain
+        today = datetime.date.today().strftime('%Y%m%d')
+        subject = 'Confirm list subscription cancelation: %s' % self.clist
+        from_email = settings.DEFAULT_FROM_EMAIL
+        to_email = self.cleaned_data['email']
+        auth = hashlib.md5('%s%s%s%s%s' % (settings.SECRET_KEY, today, to_email, 'unsubscribe', self.significant)).hexdigest()
+        context = {
+            'domain': domain,
+            'clist': self.clist,
+            'today': today,
+            'auth': auth,
+            'to_email': to_email,
+            'significant': self.significant,
+        }
+        send_mail(None, to_email, from_email, subject, 'community/public/unsubscribe_email.txt', context)
diff --git a/ietf/community/management/__init__.py b/ietf/community/management/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/ietf/community/management/commands/__init__.py b/ietf/community/management/commands/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/ietf/community/management/commands/update_community_lists.py b/ietf/community/management/commands/update_community_lists.py
new file mode 100644
index 000000000..936a6dcee
--- /dev/null
+++ b/ietf/community/management/commands/update_community_lists.py
@@ -0,0 +1,36 @@
+import sys
+import datetime
+
+from django.core.management.base import BaseCommand
+
+from ietf.community.models import Rule, CommunityList
+
+
+class Command(BaseCommand):
+    help = (u"Update drafts in community lists by reviewing their rules")
+
+
+    def handle(self, *args, **options):
+        now = datetime.datetime.now()
+        
+        rules = Rule.objects.filter(last_updated__lt=now - datetime.timedelta(hours=12))
+        count = rules.count()
+        index = 1
+        for rule in rules:
+            sys.stdout.write('Updating rule [%s/%s]\r' % (index, count))
+            sys.stdout.flush()
+            rule.save()
+            index += 1
+        if index > 1:
+            print
+        cls = CommunityList.objects.filter(cached__isnull=False)
+        count = cls.count()
+        index = 1
+        for cl in cls:
+            sys.stdout.write('Clearing community list cache [%s/%s]\r' % (index, count))
+            sys.stdout.flush()
+            cl.cached = None
+            cl.save()
+            index += 1
+        if index > 1:
+            print
diff --git a/ietf/community/management/commands/update_doc_change_dates.py b/ietf/community/management/commands/update_doc_change_dates.py
new file mode 100644
index 000000000..825edb539
--- /dev/null
+++ b/ietf/community/management/commands/update_doc_change_dates.py
@@ -0,0 +1,39 @@
+import sys
+
+from django.core.management.base import BaseCommand
+from django.db.models import Q
+
+from ietf.community.constants import SIGNIFICANT_STATES
+from ietf.community.models import DocumentChangeDates
+from redesign.doc.models import Document
+
+
+class Command(BaseCommand):
+    help = (u"Update drafts in community lists by reviewing their rules")
+
+    def handle(self, *args, **options):
+        documents = Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).distinct()
+        index = 1
+        total = documents.count()
+
+        for doc in documents:
+            (changes, created) = DocumentChangeDates.objects.get_or_create(document=doc)
+            new_version = doc.latest_event(type='new_revision')
+            normal_change = doc.latest_event()
+            significant_change = None
+            for event in doc.docevent_set.filter(type='changed_document'):
+                for state in SIGNIFICANT_STATES:
+                    if ('<b>%s</b>' % state) in event.desc:
+                        significant_change = event
+                        break
+
+            changes.new_version_date = new_version and new_version.time.date()
+            changes.normal_change_date = normal_change and normal_change.time.date()
+            changes.significant_change_date = significant_change and significant_change.time.date()
+
+            changes.save()
+
+            sys.stdout.write('Document %s/%s\r' % (index, total))
+            sys.stdout.flush()
+            index += 1
+        print
diff --git a/ietf/community/migrations/0001_initial_migration.py b/ietf/community/migrations/0001_initial_migration.py
new file mode 100644
index 000000000..df84340f4
--- /dev/null
+++ b/ietf/community/migrations/0001_initial_migration.py
@@ -0,0 +1,257 @@
+
+from south.db import db
+from django.db import models
+from ietf.community.models import *
+
+class Migration:
+    
+    def forwards(self, orm):
+        
+        # Adding model 'Rule'
+        db.create_table('community_rule', (
+            ('id', orm['community.Rule:id']),
+            ('community_list', orm['community.Rule:community_list']),
+            ('rule_type', orm['community.Rule:rule_type']),
+            ('value', orm['community.Rule:value']),
+            ('last_updated', orm['community.Rule:last_updated']),
+        ))
+        db.send_create_signal('community', ['Rule'])
+        
+        # Adding model 'CommunityList'
+        db.create_table('community_communitylist', (
+            ('id', orm['community.CommunityList:id']),
+            ('user', orm['community.CommunityList:user']),
+            ('group', orm['community.CommunityList:group']),
+        ))
+        db.send_create_signal('community', ['CommunityList'])
+        
+        # Adding ManyToManyField 'Rule.cached_ids'
+        db.create_table('community_rule_cached_ids', (
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+            ('rule', models.ForeignKey(orm.Rule, null=False)),
+            ('document', models.ForeignKey(orm['doc.Document'], null=False))
+        ))
+        
+        # Adding ManyToManyField 'CommunityList.added_ids'
+        db.create_table('community_communitylist_added_ids', (
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+            ('communitylist', models.ForeignKey(orm.CommunityList, null=False)),
+            ('document', models.ForeignKey(orm['doc.Document'], null=False))
+        ))
+        
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting model 'Rule'
+        db.delete_table('community_rule')
+        
+        # Deleting model 'CommunityList'
+        db.delete_table('community_communitylist')
+        
+        # Dropping ManyToManyField 'Rule.cached_ids'
+        db.delete_table('community_rule_cached_ids')
+        
+        # Dropping ManyToManyField 'CommunityList.added_ids'
+        db.delete_table('community_communitylist_added_ids')
+        
+    
+    
+    models = {
+        'auth.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']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+            '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': {
+            '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']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            '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']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'community.communitylist': {
+            'added_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
+        },
+        'community.rule': {
+            'cached_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'rule_type': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+            'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", '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': {
+            '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': {
+            'abstract': ('django.db.models.fields.TextField', [], {}),
+            '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']", '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'}),
+            'iana_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IanaDocStateName']", 'null': 'True', 'blank': 'True'}),
+            'iesg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IesgDocStateName']", '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'}),
+            'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'blank': 'True'}),
+            'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
+            'rfc_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RfcDocStateName']", 'null': 'True', 'blank': 'True'}),
+            'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
+            'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocStateName']", 'null': 'True', '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.DocStreamName']", 'null': 'True', 'blank': 'True'}),
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocInfoTagName']", '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'}),
+            'wg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.WgDocStateName']", 'null': 'True', 'blank': 'True'})
+        },
+        'group.group': {
+            'acronym': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}),
+            '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'})
+        },
+        'name.docinfotagname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.docstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.docstreamname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.doctypename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.groupstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.grouptypename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.ianadocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.iesgdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.intendedstdlevelname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.rfcdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.stdlevelname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.wgdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'person.email': {
+            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': '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': {
+            'address': ('django.db.models.fields.TextField', [], {'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
+        }
+    }
+    
+    complete_apps = ['community']
diff --git a/ietf/community/migrations/0002_add_display_config.py b/ietf/community/migrations/0002_add_display_config.py
new file mode 100644
index 000000000..27661721b
--- /dev/null
+++ b/ietf/community/migrations/0002_add_display_config.py
@@ -0,0 +1,231 @@
+
+from south.db import db
+from django.db import models
+from ietf.community.models import *
+
+class Migration:
+    
+    def forwards(self, orm):
+        
+        # Adding model 'DisplayConfiguration'
+        db.create_table('community_displayconfiguration', (
+            ('id', orm['community.displayconfiguration:id']),
+            ('community_list', orm['community.displayconfiguration:community_list']),
+            ('sort_method', orm['community.displayconfiguration:sort_method']),
+            ('display_fields', orm['community.displayconfiguration:display_fields']),
+        ))
+        db.send_create_signal('community', ['DisplayConfiguration'])
+        
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting model 'DisplayConfiguration'
+        db.delete_table('community_displayconfiguration')
+        
+    
+    
+    models = {
+        'auth.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']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+            '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': {
+            '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']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            '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']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'community.communitylist': {
+            'added_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
+        },
+        'community.displayconfiguration': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'display_fields': ('django.db.models.fields.TextField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'sort_method': ('django.db.models.fields.CharField', [], {'default': "'by_filename'", 'max_length': '100'})
+        },
+        'community.rule': {
+            'cached_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'rule_type': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+            'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", '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': {
+            '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': {
+            'abstract': ('django.db.models.fields.TextField', [], {}),
+            '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']", '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'}),
+            'iana_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IanaDocStateName']", 'null': 'True', 'blank': 'True'}),
+            'iesg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IesgDocStateName']", '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'}),
+            'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'blank': 'True'}),
+            'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
+            'rfc_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RfcDocStateName']", 'null': 'True', 'blank': 'True'}),
+            'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
+            'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocStateName']", 'null': 'True', '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.DocStreamName']", 'null': 'True', 'blank': 'True'}),
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocInfoTagName']", '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'}),
+            'wg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.WgDocStateName']", 'null': 'True', 'blank': 'True'})
+        },
+        'group.group': {
+            'acronym': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}),
+            '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'})
+        },
+        'name.docinfotagname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.docstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.docstreamname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.doctypename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.groupstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.grouptypename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.ianadocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.iesgdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.intendedstdlevelname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.rfcdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.stdlevelname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.wgdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'person.email': {
+            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': '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': {
+            'address': ('django.db.models.fields.TextField', [], {'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
+        }
+    }
+    
+    complete_apps = ['community']
diff --git a/ietf/community/migrations/0003_add_notifications.py b/ietf/community/migrations/0003_add_notifications.py
new file mode 100644
index 000000000..7b97730e6
--- /dev/null
+++ b/ietf/community/migrations/0003_add_notifications.py
@@ -0,0 +1,295 @@
+
+from south.db import db
+from django.db import models
+from ietf.community.models import *
+
+class Migration:
+    
+    def forwards(self, orm):
+        
+        # Adding model 'ListNotification'
+        db.create_table('community_listnotification', (
+            ('id', orm['community.listnotification:id']),
+            ('document', orm['community.listnotification:document']),
+            ('notification_date', orm['community.listnotification:notification_date']),
+            ('desc', orm['community.listnotification:desc']),
+            ('significant', orm['community.listnotification:significant']),
+        ))
+        db.send_create_signal('community', ['ListNotification'])
+        
+        # Adding model 'EmailSubscription'
+        db.create_table('community_emailsubscription', (
+            ('id', orm['community.emailsubscription:id']),
+            ('community_list', orm['community.emailsubscription:community_list']),
+            ('email', orm['community.emailsubscription:email']),
+            ('significant', orm['community.emailsubscription:significant']),
+        ))
+        db.send_create_signal('community', ['EmailSubscription'])
+        
+        # Adding model 'DocumentChangeDates'
+        db.create_table('community_documentchangedates', (
+            ('id', orm['community.documentchangedates:id']),
+            ('document', orm['community.documentchangedates:document']),
+            ('new_version_date', orm['community.documentchangedates:new_version_date']),
+            ('normal_change_date', orm['community.documentchangedates:normal_change_date']),
+            ('significant_change_date', orm['community.documentchangedates:significant_change_date']),
+        ))
+        db.send_create_signal('community', ['DocumentChangeDates'])
+        
+        # Adding model 'ExpectedChange'
+        db.create_table('community_expectedchange', (
+            ('id', orm['community.expectedchange:id']),
+            ('community_list', orm['community.expectedchange:community_list']),
+            ('document', orm['community.expectedchange:document']),
+            ('expected_date', orm['community.expectedchange:expected_date']),
+        ))
+        db.send_create_signal('community', ['ExpectedChange'])
+        
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting model 'ListNotification'
+        db.delete_table('community_listnotification')
+        
+        # Deleting model 'EmailSubscription'
+        db.delete_table('community_emailsubscription')
+        
+        # Deleting model 'DocumentChangeDates'
+        db.delete_table('community_documentchangedates')
+        
+        # Deleting model 'ExpectedChange'
+        db.delete_table('community_expectedchange')
+        
+    
+    
+    models = {
+        'auth.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']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+            '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': {
+            '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']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            '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']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'community.communitylist': {
+            'added_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
+        },
+        'community.displayconfiguration': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'display_fields': ('django.db.models.fields.TextField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'sort_method': ('django.db.models.fields.CharField', [], {'default': "'by_filename'", 'max_length': '100'})
+        },
+        'community.documentchangedates': {
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_version_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'normal_change_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'significant_change_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+        },
+        'community.emailsubscription': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'email': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'significant': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+        },
+        'community.expectedchange': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'expected_date': ('django.db.models.fields.DateField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'community.listnotification': {
+            'desc': ('django.db.models.fields.TextField', [], {}),
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'notification_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'significant': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+        },
+        'community.rule': {
+            'cached_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'rule_type': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+            'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", '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': {
+            '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': {
+            'abstract': ('django.db.models.fields.TextField', [], {}),
+            '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']", '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'}),
+            'iana_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IanaDocStateName']", 'null': 'True', 'blank': 'True'}),
+            'iesg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IesgDocStateName']", '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'}),
+            'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'blank': 'True'}),
+            'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
+            'rfc_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.RfcDocStateName']", 'null': 'True', 'blank': 'True'}),
+            'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
+            'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocStateName']", 'null': 'True', '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.DocStreamName']", 'null': 'True', 'blank': 'True'}),
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocInfoTagName']", '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'}),
+            'wg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.WgDocStateName']", 'null': 'True', 'blank': 'True'})
+        },
+        'group.group': {
+            'acronym': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}),
+            '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'})
+        },
+        'name.docinfotagname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.docstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.docstreamname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.doctypename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.groupstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.grouptypename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.ianadocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.iesgdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.intendedstdlevelname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.rfcdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.stdlevelname': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'name.wgdocstatename': {
+            'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            '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', 'blank': 'True'})
+        },
+        'person.email': {
+            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': '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': {
+            'address': ('django.db.models.fields.TextField', [], {'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
+        }
+    }
+    
+    complete_apps = ['community']
diff --git a/ietf/community/migrations/0004_refactor_notifications_with_docevent.py b/ietf/community/migrations/0004_refactor_notifications_with_docevent.py
new file mode 100644
index 000000000..f1bf69725
--- /dev/null
+++ b/ietf/community/migrations/0004_refactor_notifications_with_docevent.py
@@ -0,0 +1,262 @@
+
+from south.db import db
+from django.db import models
+from ietf.community.models import *
+
+class Migration:
+    
+    def forwards(self, orm):
+        
+        # Adding field 'ListNotification.event'
+        db.add_column('community_listnotification', 'event', orm['community.listnotification:event'])
+        
+        # Deleting field 'ListNotification.document'
+        db.delete_column('community_listnotification', 'document_id')
+        
+        # Deleting field 'ListNotification.notification_date'
+        db.delete_column('community_listnotification', 'notification_date')
+        
+        # Deleting field 'ListNotification.desc'
+        db.delete_column('community_listnotification', 'desc')
+        
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting field 'ListNotification.event'
+        db.delete_column('community_listnotification', 'event_id')
+        
+        # Adding field 'ListNotification.document'
+        db.add_column('community_listnotification', 'document', orm['community.listnotification:document'])
+        
+        # Adding field 'ListNotification.notification_date'
+        db.add_column('community_listnotification', 'notification_date', orm['community.listnotification:notification_date'])
+        
+        # Adding field 'ListNotification.desc'
+        db.add_column('community_listnotification', 'desc', orm['community.listnotification:desc'])
+        
+    
+    
+    models = {
+        'auth.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']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+            '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': {
+            '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']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            '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']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
+        },
+        'community.communitylist': {
+            'added_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
+        },
+        'community.displayconfiguration': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'display_fields': ('django.db.models.fields.TextField', [], {'default': "'filename,title,date'"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'sort_method': ('django.db.models.fields.CharField', [], {'default': "'by_filename'", 'max_length': '100'})
+        },
+        'community.documentchangedates': {
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_version_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'normal_change_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'significant_change_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+        },
+        'community.emailsubscription': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'email': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'significant': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+        },
+        'community.expectedchange': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'expected_date': ('django.db.models.fields.DateField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'community.listnotification': {
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'significant': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+        },
+        'community.rule': {
+            'cached_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'rule_type': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+            'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", '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': {
+            '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.docevent': {
+            'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
+            'desc': ('django.db.models.fields.TextField', [], {}),
+            'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'doc.document': {
+            'abstract': ('django.db.models.fields.TextField', [], {}),
+            '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']", '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'}),
+            'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", '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']", '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.DocStreamName']", 'null': 'True', 'blank': 'True'}),
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'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.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', [], {'to': "orm['doc.State']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
+            'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
+            'used': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'})
+        },
+        'doc.statetype': {
+            'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
+        },
+        'group.group': {
+            'acronym': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '16', 'blank': 'True'}),
+            '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'}),
+            'iesg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IesgGroupStateName']", 'null': 'True', 'blank': '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']"}),
+            'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']"})
+        },
+        'name.docstreamname': {
+            '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        'name.iesggroupstatename': {
+            '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        'person.email': {
+            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': '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': {
+            '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 = ['community']
diff --git a/ietf/community/migrations/0005_auto__add_field_communitylist_secret.py b/ietf/community/migrations/0005_auto__add_field_communitylist_secret.py
new file mode 100644
index 000000000..1ea3cf4bf
--- /dev/null
+++ b/ietf/community/migrations/0005_auto__add_field_communitylist_secret.py
@@ -0,0 +1,245 @@
+
+from south.db import db
+from django.db import models
+from ietf.community.models import *
+
+class Migration:
+    
+    def forwards(self, orm):
+        
+        # Adding field 'CommunityList.secret'
+        db.add_column('community_communitylist', 'secret', orm['community.communitylist:secret'])
+        
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting field 'CommunityList.secret'
+        db.delete_column('community_communitylist', 'secret')
+        
+    
+    
+    models = {
+        'auth.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']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+            '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': {
+            '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']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            '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']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
+        },
+        'community.communitylist': {
+            'added_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
+        },
+        'community.displayconfiguration': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'display_fields': ('django.db.models.fields.TextField', [], {'default': "'filename,title,date'"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'sort_method': ('django.db.models.fields.CharField', [], {'default': "'by_filename'", 'max_length': '100'})
+        },
+        'community.documentchangedates': {
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_version_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'normal_change_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'significant_change_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+        },
+        'community.emailsubscription': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'email': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'significant': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+        },
+        'community.expectedchange': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'expected_date': ('django.db.models.fields.DateField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'community.listnotification': {
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'significant': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+        },
+        'community.rule': {
+            'cached_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'rule_type': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+            'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", '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': {
+            '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.docevent': {
+            'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
+            'desc': ('django.db.models.fields.TextField', [], {}),
+            'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'doc.document': {
+            'abstract': ('django.db.models.fields.TextField', [], {}),
+            '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']", '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'}),
+            'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", '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']", '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.DocStreamName']", 'null': 'True', 'blank': 'True'}),
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'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.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', [], {'to': "orm['doc.State']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
+            'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
+            'used': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'})
+        },
+        'doc.statetype': {
+            'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
+        },
+        'group.group': {
+            'acronym': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '16', 'blank': 'True'}),
+            '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'}),
+            'iesg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IesgGroupStateName']", 'null': 'True', 'blank': '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']"}),
+            'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']"})
+        },
+        'name.docstreamname': {
+            '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        'name.iesggroupstatename': {
+            '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        'person.email': {
+            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': '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': {
+            '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 = ['community']
diff --git a/ietf/community/migrations/0006_auto__add_field_communitylist_cached.py b/ietf/community/migrations/0006_auto__add_field_communitylist_cached.py
new file mode 100644
index 000000000..d566e2758
--- /dev/null
+++ b/ietf/community/migrations/0006_auto__add_field_communitylist_cached.py
@@ -0,0 +1,246 @@
+
+from south.db import db
+from django.db import models
+from ietf.community.models import *
+
+class Migration:
+    
+    def forwards(self, orm):
+        
+        # Adding field 'CommunityList.cached'
+        db.add_column('community_communitylist', 'cached', orm['community.communitylist:cached'])
+        
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting field 'CommunityList.cached'
+        db.delete_column('community_communitylist', 'cached')
+        
+    
+    
+    models = {
+        'auth.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']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+            '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': {
+            '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']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            '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']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
+        },
+        'community.communitylist': {
+            'added_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'cached': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
+        },
+        'community.displayconfiguration': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'display_fields': ('django.db.models.fields.TextField', [], {'default': "'filename,title,date'"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'sort_method': ('django.db.models.fields.CharField', [], {'default': "'by_filename'", 'max_length': '100'})
+        },
+        'community.documentchangedates': {
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'new_version_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'normal_change_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'significant_change_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+        },
+        'community.emailsubscription': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'email': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'significant': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+        },
+        'community.expectedchange': {
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'expected_date': ('django.db.models.fields.DateField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        'community.listnotification': {
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'significant': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+        },
+        'community.rule': {
+            'cached_ids': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.Document']"}),
+            'community_list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['community.CommunityList']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'rule_type': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+            'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", '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': {
+            '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.docevent': {
+            'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
+            'desc': ('django.db.models.fields.TextField', [], {}),
+            'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'doc.document': {
+            'abstract': ('django.db.models.fields.TextField', [], {}),
+            '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']", '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'}),
+            'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", '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']", '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.DocStreamName']", 'null': 'True', 'blank': 'True'}),
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'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.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', [], {'to': "orm['doc.State']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
+            'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
+            'used': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'})
+        },
+        'doc.statetype': {
+            'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
+        },
+        'group.group': {
+            'acronym': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '16', 'blank': 'True'}),
+            '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'}),
+            'iesg_state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IesgGroupStateName']", 'null': 'True', 'blank': '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']"}),
+            'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']"})
+        },
+        'name.docstreamname': {
+            '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        'name.iesggroupstatename': {
+            '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        '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', 'blank': 'True'})
+        },
+        'person.email': {
+            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': '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': {
+            '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 = ['community']
diff --git a/ietf/community/migrations/__init__.py b/ietf/community/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/ietf/community/models.py b/ietf/community/models.py
new file mode 100644
index 000000000..6062e87e0
--- /dev/null
+++ b/ietf/community/models.py
@@ -0,0 +1,262 @@
+import hashlib
+
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.core.urlresolvers import reverse
+from django.db import models
+from django.db.models import signals, Q
+
+from ietf.utils.mail import send_mail
+from redesign.doc.models import Document, DocEvent
+from redesign.group.models import Group, Role
+
+from ietf.community.rules import TYPES_OF_RULES, RuleManager
+from ietf.community.display import (TYPES_OF_SORT, DisplayField,
+                                    SortMethod)
+from ietf.community.constants import SIGNIFICANT_STATES
+
+
+class CommunityList(models.Model):
+
+    user = models.ForeignKey(User, blank=True, null=True)
+    group = models.ForeignKey(Group, blank=True, null=True)
+    added_ids = models.ManyToManyField(Document)
+    secret = models.CharField(max_length=255, null=True, blank=True)
+    cached = models.TextField(null=True, blank=True)
+
+    def check_manager(self, user):
+        if user == self.user:
+            return True
+        if not self.group or self.group.type.slug not in ('area', 'wg'):
+            return False
+        try:
+            person = user.get_profile()
+        except:
+            return False
+        if self.group.type.slug == 'area':
+            return bool(Role.objects.filter(name__slug='ad', email__in=person.email_set.all(), group=self.group).count())
+        elif self.group.type.slug == 'wg':
+            return bool(Role.objects.filter(name__slug='chair', email__in=person.email_set.all(), group=self.group).count())
+        return False
+
+    def short_name(self):
+        if self.user:
+            return 'Personal list'
+        else:
+            return '%s list' % self.group.acronym
+
+    def long_name(self):
+        if self.user:
+            return 'Personal ID list of %s' % self.user.username
+        else:
+            return 'ID list for %s' % self.group.name
+
+    def __unicode__(self):
+        return self.long_name()
+
+    def get_public_url(self):
+        if self.user:
+            return reverse('view_personal_list', None, args=(self.user.username, ))
+        else:
+            return reverse('view_group_list', None, args=(self.group.acronym, ))
+
+    def get_manage_url(self):
+        if self.user:
+            return reverse('manage_personal_list', None, args=())
+        else:
+            return reverse('manage_group_list', None, args=(self.group.acronym, ))
+
+    def get_display_config(self):
+        dconfig = getattr(self, '_cached_dconfig', None)
+        if not dconfig:
+            self._cached_dconfig = DisplayConfiguration.objects.get_or_create(community_list=self)[0]
+            return self._cached_dconfig
+        return self._cached_dconfig
+
+    def get_documents(self):
+        if hasattr(self, '_cached_documents'):
+            return self._cached_documents
+        docs = self.added_ids.all().distinct().select_related('type', 'group', 'ad')
+        for rule in self.rule_set.all():
+            docs = docs | rule.cached_ids.all().distinct()
+        sort_field = self.get_display_config().get_sort_method().get_sort_field()
+        docs = docs.distinct().order_by(sort_field)
+        self._cached_documents = docs
+        return self._cached_documents
+
+    def get_rfcs_and_drafts(self):
+        if hasattr(self, '_cached_rfcs_and_drafts'):
+            return self._cached_rfcs_and_drafts
+        docs = self.get_documents()
+        sort_method = self.get_display_config().get_sort_method()
+        sort_field = sort_method.get_sort_field()
+        if hasattr(sort_method, 'get_full_rfc_sort'):
+            rfcs = sort_method.get_full_rfc_sort(docs.filter(states__name='rfc').distinct())
+        else:
+            rfcs = docs.filter(states__name='rfc').distinct().order_by(sort_field)
+        if hasattr(sort_method, 'get_full_draft_sort'):
+            drafts = sort_method.get_full_draft_sort(docs.exclude(pk__in=rfcs).distinct())
+        else:
+            drafts = docs.exclude(pk__in=rfcs).distinct().order_by(sort_field)
+        self._cached_rfcs_and_drafts = (rfcs, drafts)
+        return self._cached_rfcs_and_drafts
+
+    def add_subscriptor(self, email, significant):
+        self.emailsubscription_set.get_or_create(email=email, significant=significant)
+
+    def save(self, *args, **kwargs):
+        super(CommunityList, self).save(*args, **kwargs)
+        if not self.secret:
+            self.secret = hashlib.md5('%s%s%s%s' % (settings.SECRET_KEY, self.id, self.user and self.user.id or '', self.group and self.group.id or '')).hexdigest()
+            self.save()
+
+    def update(self):
+        self.cached=None
+        self.save()
+
+
+class Rule(models.Model):
+
+    community_list = models.ForeignKey(CommunityList)
+    cached_ids = models.ManyToManyField(Document)
+
+    rule_type = models.CharField(
+        max_length=30,
+        choices=TYPES_OF_RULES)
+    value = models.CharField(
+        max_length=255)
+
+    last_updated = models.DateTimeField(
+        auto_now=True)
+
+    def get_callable_rule(self):
+        for i in RuleManager.__subclasses__():
+            if i.codename == self.rule_type:
+                return i(self.value)
+        return RuleManager(self.value)
+
+    def save(self, *args, **kwargs):
+        super(Rule, self).save(*args, **kwargs)
+        rule = self.get_callable_rule()
+        self.cached_ids = rule.get_documents()
+        self.community_list.update()
+
+    def delete(self):
+        self.community_list.update()
+        super(Rule, self).delete()
+
+
+class DisplayConfiguration(models.Model):
+
+    community_list = models.ForeignKey(CommunityList)
+    sort_method = models.CharField(
+        max_length=100,
+        choices=TYPES_OF_SORT,
+        default='by_filename',
+        blank=False,
+        null=False)
+    display_fields = models.TextField(
+        default='filename,title,date')
+
+    def get_display_fields_config(self):
+        fields = self.display_fields and self.display_fields.split(',') or []
+        config = []
+        for i in DisplayField.__subclasses__():
+            config.append({
+                'codename': i.codename,
+                'description': i.description,
+                'active': i.codename in fields,
+            })
+        return config
+
+    def get_active_fields(self):
+        fields = self.display_fields and self.display_fields.split(',') or ''
+        active_fields = [i for i in DisplayField.__subclasses__() if i.codename in fields]
+        return active_fields
+
+    def get_all_fields(self):
+        all_fields = [i for i in DisplayField.__subclasses__()]
+        return all_fields
+
+    def get_sort_method(self):
+        for i in SortMethod.__subclasses__():
+            if i.codename == self.sort_method:
+                return i()
+        return SortMethod()
+
+    def save(self, *args, **kwargs):
+        super(DisplayConfiguration, self).save(*args, **kwargs)
+        self.community_list.update()
+
+    def delete(self):
+        self.community_list.update()
+        super(DisplayConfiguration, self).delete()
+
+
+class ExpectedChange(models.Model):
+
+    community_list = models.ForeignKey(CommunityList)
+    document = models.ForeignKey(Document)
+    expected_date = models.DateField(
+        verbose_name='Expected date'
+        )
+
+
+class EmailSubscription(models.Model):
+    community_list = models.ForeignKey(CommunityList)
+    email = models.CharField(max_length=200)
+    significant = models.BooleanField(default=False)
+
+
+class ListNotification(models.Model):
+
+    event = models.ForeignKey(DocEvent)
+    significant = models.BooleanField(default=False)
+
+    def notify_by_email(self):
+        clists = CommunityList.objects.filter(
+            Q(added_ids=self.event.doc) | Q(rule__cached_ids=self.event.doc)).distinct()
+        from_email = settings.DEFAULT_FROM_EMAIL
+        for l in clists:
+            subject = '%s notification: Changes on %s' % (l.long_name(), self.event.doc.name)
+            context = {'notification': self.event,
+                       'clist': l}
+            to_email = ''
+            filter_subscription = {'community_list': l}
+            if not self.significant:
+                filter_subscription['significant'] = False
+            bcc = ','.join(list(set([i.email for i in EmailSubscription.objects.filter(**filter_subscription)])))
+            send_mail(None, to_email, from_email, subject, 'community/public/notification_email.txt', context, bcc=bcc)
+
+
+def notify_events(sender, instance, **kwargs):
+    if not isinstance(instance, DocEvent):
+        return
+    if instance.doc.type.slug != 'draft' or instance.type == 'added_comment':
+        return
+    (changes, created) = DocumentChangeDates.objects.get_or_create(document=instance.doc)
+    changes.normal_change_date = instance.time
+    significant = False
+    if instance.type == 'changed_document' and 'tate changed' in instance.desc:
+        for i in SIGNIFICANT_STATES:
+            if ('<b>%s</b>' % i) in instance.desc:
+                significant = True
+                changes.significant_change_date = instance.time
+                break
+    elif instance.type == 'new_revision':
+        changes.new_version_date = instance.time
+    changes.save()
+    notification = ListNotification.objects.create(
+        event=instance,
+        significant=significant,
+    )
+    notification.notify_by_email()
+signals.post_save.connect(notify_events)
+
+
+class DocumentChangeDates(models.Model):
+
+    document = models.ForeignKey(Document)
+    new_version_date = models.DateTimeField(blank=True, null=True)
+    normal_change_date = models.DateTimeField(blank=True, null=True)
+    significant_change_date = models.DateTimeField(blank=True, null=True)
diff --git a/ietf/community/rules.py b/ietf/community/rules.py
new file mode 100644
index 000000000..2607e5ea3
--- /dev/null
+++ b/ietf/community/rules.py
@@ -0,0 +1,139 @@
+from django.db.models import Q
+
+from ietf.community.utils import get_documents_with
+
+from redesign.doc.models import Document
+from redesign.group.models import Group
+from redesign.person.models import Person
+
+
+class RuleManager(object):
+
+    codename = ''
+    description = ''
+
+    def __init__(self, value):
+        self.value = self.get_value(value)
+
+    def get_value(self, value):
+        return value
+
+    def get_documents(self):
+        return Document.objects.none()
+
+    def options(self):
+        return None
+
+    def show_value(self):
+        return self.value
+
+
+class WgAsociatedRule(RuleManager):
+    codename = 'wg_asociated'
+    description = 'All I-Ds associated with a particular WG'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(group__acronym=self.value).distinct()
+
+    def options(self):
+        return [(i.acronym, i.name) for i in Group.objects.filter(type='wg', state='active').distinct().order_by('name')]
+
+    def show_value(self):
+        try:
+            return Group.objects.get(acronym=self.value).name
+        except Group.DoesNotExist:
+            return self.value
+
+
+class AreaAsociatedRule(RuleManager):
+    codename = 'area_asociated'
+    description = 'All I-Ds associated with all WGs in a particular Area'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(group__parent__acronym=self.value, group__parent__type='area').distinct()
+
+    def options(self):
+        return [(i.acronym, i.name) for i in Group.objects.filter(type='area', state='active').distinct().order_by('name')]
+
+    def show_value(self):
+        try:
+            return Group.objects.get(acronym=self.value).name
+        except Group.DoesNotExist:
+            return self.value
+
+
+class AdResponsibleRule(RuleManager):
+    codename = 'ad_responsible'
+    description = 'All I-Ds with a particular responsible AD'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(ad=self.value).distinct()
+
+    def options(self):
+        return [(i.pk, i.name) for i in Person.objects.filter(role__name='ad').distinct().order_by('name')]
+
+    def show_value(self):
+        try:
+            return Person.objects.get(pk=self.value).name
+        except Person.DoesNotExist:
+            return self.value
+
+
+class AuthorRule(RuleManager):
+    codename = 'author'
+    description = 'All I-Ds with a particular author'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(authors__person__name__icontains=self.value).distinct()
+
+
+class ShepherdRule(RuleManager):
+    codename = 'shepherd'
+    description = 'All I-Ds with a particular document shepherd'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(shepherd__name__icontains=self.value).distinct()
+
+
+class ReferenceToRFCRule(RuleManager):
+    codename = 'reference_to_rfc'
+    description = 'All I-Ds that have a reference to a particular RFC'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(relateddocument__target__document__states__name='rfc', relateddocument__target__document__name__icontains=self.value).distinct()
+
+
+class ReferenceToIDRule(RuleManager):
+    codename = 'reference_to_id'
+    description = 'All I-Ds that have a reference to a particular I-D'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(relateddocument__target__document__type__name='Draft', relateddocument__target__document__name__icontains=self.value).distinct()
+
+
+class ReferenceFromRFCRule(RuleManager):
+    codename = 'reference_from_rfc'
+    description = 'All I-Ds that are referenced by a particular RFC'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(relateddocument__source__states__name='rfc', relateddocument__source__name__icontains=self.value).distinct()
+
+
+
+class ReferenceFromIDRule(RuleManager):
+    codename = 'reference_from_id'
+    description = 'All I-Ds that are referenced by a particular I-D'
+
+    def get_documents(self):
+        return Document.objects.filter(Q(type__name='Draft') | Q(states__name='rfc')).filter(relateddocument__source__type__name='Draft', relateddocument__source__name__icontains=self.value).distinct()
+
+
+class WithTextRule(RuleManager):
+    codename = 'with_text'
+    description = 'All I-Ds that contain a particular text string'
+
+    def get_documents(self):
+        return get_documents_with(self.value).distinct()
+
+
+TYPES_OF_RULES = [(i.codename, i.description) for i in RuleManager.__subclasses__()]
diff --git a/ietf/community/templatetags/__init__.py b/ietf/community/templatetags/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/ietf/community/templatetags/community_tags.py b/ietf/community/templatetags/community_tags.py
new file mode 100644
index 000000000..9a9bb0e18
--- /dev/null
+++ b/ietf/community/templatetags/community_tags.py
@@ -0,0 +1,80 @@
+from django import template
+from django.template.loader import render_to_string
+
+from ietf.community.models import CommunityList
+from redesign.group.models import Role
+
+
+register = template.Library()
+
+
+class CommunityListNode(template.Node):
+    
+    def __init__(self, user, var_name):
+        self.user = user
+        self.var_name = var_name
+
+    def render(self, context):
+        user = self.user.resolve(context)
+        if not user or not user.is_authenticated():
+            return ''
+        lists = {'personal': CommunityList.objects.get_or_create(user=user)[0]}
+        try:
+            person = user.get_profile()
+            groups = []
+            managed_areas = [i.group for i in Role.objects.filter(name__slug='ad', email__in=person.email_set.all())]
+            for area in managed_areas:
+                groups.append(CommunityList.objects.get_or_create(group=area)[0])
+            managed_wg = [i.group for i in Role.objects.filter(name__slug='chair', group__type__slug='wg', email__in=person.email_set.all())]
+            for wg in managed_wg:
+                groups.append(CommunityList.objects.get_or_create(group=wg)[0])
+            lists['group'] = groups
+        except:
+            pass
+        context.update({self.var_name: lists})
+        return ''
+
+
+@register.tag
+def get_user_managed_lists(parser, token):
+    firstbits = token.contents.split(None, 2)
+    if len(firstbits) != 3:
+        raise template.TemplateSyntaxError("'get_user_managed_lists' tag takes three arguments")
+    user = parser.compile_filter(firstbits[1])
+    lastbits_reversed = firstbits[2][::-1].split(None, 2)
+    if lastbits_reversed[1][::-1] != 'as':
+        raise template.TemplateSyntaxError("next-to-last argument to 'get_user_managed_lists' tag must"
+                                  " be 'as'")
+    var_name = lastbits_reversed[0][::-1]
+    return CommunityListNode(user, var_name)
+
+
+@register.inclusion_tag('community/display_field.html', takes_context=False)
+def show_field(field, doc):
+    return {'field': field,
+            'value': field().get_value(doc),
+           }
+
+
+class CommunityListViewNode(template.Node):
+    
+    def __init__(self, clist):
+        self.clist = clist
+
+    def render(self, context):
+        clist = self.clist.resolve(context)
+        if not clist.cached:
+            clist.cached = render_to_string('community/raw_view.html',
+                                            {'cl': clist,
+                                             'dc': clist.get_display_config()})
+            clist.save()
+        return clist.cached
+
+
+@register.tag
+def get_clist_view(parser, token):
+    firstbits = token.contents.split(None, 1)
+    if len(firstbits) != 2:
+        raise template.TemplateSyntaxError("'get_clist_view' tag takes one argument")
+    clist = parser.compile_filter(firstbits[1])
+    return CommunityListViewNode(clist)
diff --git a/ietf/community/urls.py b/ietf/community/urls.py
new file mode 100644
index 000000000..4f066c7d8
--- /dev/null
+++ b/ietf/community/urls.py
@@ -0,0 +1,32 @@
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('ietf.community.views',
+    url(r'^personal/$', 'manage_personal_list', name='manage_personal_list'),
+    url(r'^personal/csv/$', 'csv_personal_list', name='csv_personal_list'),
+    url(r'^personal/(?P<secret>[a-f0-9]+)/view/$', 'view_personal_list', name='view_personal_list'),
+    url(r'^personal/(?P<secret>[a-f0-9]+)/changes/feed/$', 'changes_personal_list', name='changes_personal_list'),
+    url(r'^personal/(?P<secret>[a-f0-9]+)/changes/significant/feed/$', 'significant_personal_list', name='significant_personal_list'),
+    url(r'^personal/(?P<secret>[a-f0-9]+)/subscribe/$', 'subscribe_personal_list', {'significant': False}, name='subscribe_personal_list'),
+    url(r'^personal/(?P<secret>[a-f0-9]+)/subscribe/significant/$', 'subscribe_personal_list', {'significant': True}, name='subscribe_significant_personal_list'),
+    url(r'^personal/(?P<secret>[a-f0-9]+)/unsubscribe/$', 'unsubscribe_personal_list', {'significant': False}, name='unsubscribe_personal_list'),
+    url(r'^personal/(?P<secret>[a-f0-9]+)/unsubscribe/significant/$', 'unsubscribe_personal_list', {'significant': True}, name='unsubscribe_significant_personal_list'),
+
+    url(r'^group/(?P<acronym>[\w.@+-]+)/$', 'manage_group_list', name='manage_group_list'),
+    url(r'^group/(?P<acronym>[\w.@+-]+)/view/$', 'view_group_list', name='view_group_list'),
+    url(r'^group/(?P<acronym>[\w.@+-]+)/changes/feed/$', 'changes_group_list', name='changes_group_list'),
+    url(r'^group/(?P<acronym>[\w.@+-]+)/changes/significant/feed/$', 'significant_group_list', name='significant_group_list'),
+    url(r'^group/(?P<acronym>[\w.@+-]+)/csv/$', 'csv_group_list', name='csv_group_list'),
+    url(r'^group/(?P<acronym>[\w.@+-]+)/subscribe/$', 'subscribe_group_list', {'significant': False}, name='subscribe_group_list'),
+    url(r'^group/(?P<acronym>[\w.@+-]+)/subscribe/significant/$', 'subscribe_group_list', {'significant': True}, name='subscribe_significant_group_list'),
+    url(r'^group/(?P<acronym>[\w.@+-]+)/unsubscribe/$', 'unsubscribe_group_list', {'significant': False}, name='unsubscribe_group_list'),
+    url(r'^group/(?P<acronym>[\w.@+-]+)/unsubscribe/significant/$', 'unsubscribe_group_list', {'significant': True}, name='unsubscribe_significant_group_list'),
+
+    url(r'^add_document/(?P<document_name>[^/]+)/$', 'add_document', name='community_add_document'),
+    url(r'^(?P<list_id>[\d]+)/remove_document/(?P<document_name>[^/]+)/$', 'remove_document', name='community_remove_document'),
+    url(r'^(?P<list_id>[\d]+)/remove_rule/(?P<rule_id>[^/]+)/$', 'remove_rule', name='community_remove_rule'),
+    url(r'^(?P<list_id>[\d]+)/subscribe/confirm/(?P<email>[\w.@+-]+)/(?P<date>[\d]+)/(?P<confirm_hash>[a-f0-9]+)/$', 'confirm_subscription', name='confirm_subscription'),
+    url(r'^(?P<list_id>[\d]+)/subscribe/significant/confirm/(?P<email>[\w.@+-]+)/(?P<date>[\d]+)/(?P<confirm_hash>[a-f0-9]+)/$', 'confirm_significant_subscription', name='confirm_significant_subscription'),
+    url(r'^(?P<list_id>[\d]+)/unsubscribe/confirm/(?P<email>[\w.@+-]+)/(?P<date>[\d]+)/(?P<confirm_hash>[a-f0-9]+)/$', 'confirm_unsubscription', name='confirm_unsubscription'),
+    url(r'^(?P<list_id>[\d]+)/unsubscribe/significant/confirm/(?P<email>[\w.@+-]+)/(?P<date>[\d]+)/(?P<confirm_hash>[a-f0-9]+)/$', 'confirm_significant_unsubscription', name='confirm_significant_unsubscription'),
+)
diff --git a/ietf/community/utils.py b/ietf/community/utils.py
new file mode 100644
index 000000000..7b4f325e0
--- /dev/null
+++ b/ietf/community/utils.py
@@ -0,0 +1,43 @@
+import subprocess
+
+from django.conf import settings
+
+from redesign.doc.models import Document
+
+
+def search_files(files, text):
+    p = subprocess.Popen(['grep', "-l", text] + files, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    stdout, stderr = p.communicate()
+    paths = stdout.strip().split('\n')
+    return paths
+
+
+def get_drafts_with(text):
+    draft_dir = settings.INTERNET_DRAFT_PATH
+    last_files = ['%s%s-%s.txt' % (draft_dir, i.name, i.rev) for i in Document.objects.filter(type='draft')]
+    paths = search_files(last_files, text)
+    result = []
+    for i in paths:
+        result.append(i.replace(draft_dir, '')[:-7])
+    return Document.objects.filter(type='draft', name__in=result)
+
+def search_in_path(path, text):
+    p = subprocess.Popen(['grep', "-rl", text, path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    stdout, stderr = p.communicate()
+    paths = stdout.strip().split('\n')
+    return paths
+
+def get_rfcs_with(text):
+    rfc_dir = settings.RFC_PATH
+    paths = search_in_path(rfc_dir, text)
+    result = []
+    for i in paths:
+        if i.endswith('.txt'):
+            result.append(i.replace(rfc_dir, '')[:-4])
+    return Document.objects.filter(type='draft', docalias__name__in=result)
+
+def get_documents_with(text):
+    drafts = get_drafts_with(text)
+    rfcs = get_rfcs_with(text)
+    documents = drafts | rfcs
+    return documents.distinct()
diff --git a/ietf/community/views.py b/ietf/community/views.py
new file mode 100644
index 000000000..5efb3abf9
--- /dev/null
+++ b/ietf/community/views.py
@@ -0,0 +1,329 @@
+import csv
+import uuid
+import datetime
+import hashlib
+
+from django.conf import settings
+from django.contrib.auth import REDIRECT_FIELD_NAME
+from django.contrib.auth.models import User
+from django.http import HttpResponse, Http404, HttpResponseRedirect
+from django.shortcuts import get_object_or_404, render_to_response
+from django.template import RequestContext
+from django.utils import simplejson
+from django.utils.http import urlquote
+
+from ietf.community.models import CommunityList, Rule, EmailSubscription, ListNotification
+from ietf.community.forms import RuleForm, DisplayForm, SubscribeForm, UnSubscribeForm
+from redesign.group.models import Group
+from redesign.doc.models import Document, DocEvent
+
+
+def _manage_list(request, clist):
+    display_config = clist.get_display_config()
+    if request.method == 'POST' and request.POST.get('save_rule', None):
+        rule_form = RuleForm(request.POST, clist=clist)
+        display_form = DisplayForm(instance=display_config)
+        if rule_form.is_valid():
+            rule_form.save()
+            rule_form = RuleForm(clist=clist)
+            display_form = DisplayForm(instance=display_config)
+    elif request.method == 'POST' and request.POST.get('save_display', None):
+        display_form = DisplayForm(request.POST, instance=display_config)
+        rule_form = RuleForm(clist=clist)
+        if display_form.is_valid():
+            display_form.save()
+            rule_form = RuleForm(clist=clist)
+            display_form = DisplayForm(instance=display_config)
+    else:
+        rule_form = RuleForm(clist=clist)
+        display_form = DisplayForm(instance=display_config)
+    clist = CommunityList.objects.get(id=clist.id)
+    return render_to_response('community/manage_clist.html',
+                              {'cl': clist,
+                               'dc': display_config,
+                               'display_form': display_form,
+                               'rule_form': rule_form},
+                              context_instance=RequestContext(request))
+
+
+def manage_personal_list(request):
+    user = request.user
+    if not user.is_authenticated():
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    clist = CommunityList.objects.get_or_create(user=request.user)[0]
+    if not clist.check_manager(request.user):
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    return _manage_list(request, clist)
+
+
+def manage_group_list(request, acronym):
+    group = get_object_or_404(Group, acronym=acronym)
+    if group.type.slug not in ('area', 'wg'):
+        raise Http404
+    clist = CommunityList.objects.get_or_create(group=group)[0]
+    if not clist.check_manager(request.user):
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    return _manage_list(request, clist)
+
+
+def add_document(request, document_name):
+    if not request.user.is_authenticated():
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    doc = get_object_or_404(Document, name=document_name)
+    clist = CommunityList.objects.get_or_create(user=request.user)[0]
+    clist.update()
+    return add_document_to_list(request, clist, doc)
+
+
+def remove_document(request, list_id, document_name):
+    clist = get_object_or_404(CommunityList, pk=list_id)
+    if not clist.check_manager(request.user):
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    doc = get_object_or_404(Document, name=document_name)
+    clist.added_ids.remove(doc)
+    clist.update()
+    return HttpResponseRedirect(clist.get_manage_url())
+
+
+def add_document_to_list(request, clist, doc):
+    if not clist.check_manager(request.user):
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    clist.added_ids.add(doc)
+    return HttpResponse(simplejson.dumps({'success': True}), mimetype='text/plain')
+
+
+def remove_rule(request, list_id, rule_id):
+    clist = get_object_or_404(CommunityList, pk=list_id)
+    if not clist.check_manager(request.user):
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    rule = get_object_or_404(Rule, pk=rule_id)
+    rule.delete()
+    return HttpResponseRedirect(clist.get_manage_url())
+
+
+def _view_list(request, clist):
+    display_config = clist.get_display_config()
+    return render_to_response('community/public/view_list.html',
+                              {'cl': clist,
+                               'dc': display_config,
+                              },
+                              context_instance=RequestContext(request))
+
+
+def view_personal_list(request, secret):
+    clist = get_object_or_404(CommunityList, secret=secret)
+    return _view_list(request, clist)
+
+
+def view_group_list(request, acronym):
+    group = get_object_or_404(Group, acronym=acronym)
+    clist = get_object_or_404(CommunityList, group=group)
+    return _view_list(request, clist)
+
+
+def _atom_view(request, clist, significant=False):
+    documents = [i['pk'] for i in clist.get_documents().values('pk')]
+    notifications = DocEvent.objects.filter(doc__pk__in=documents)\
+                                            .distinct()\
+                                            .order_by('-time', '-id')
+    if significant:
+        notifications = notifications.filter(listnotification__significant=True)
+
+    host = request.get_host()
+    feed_url = 'http://%s%s' % (host, request.get_full_path())
+    feed_id = uuid.uuid5(uuid.NAMESPACE_URL, feed_url.encode('utf-8'))
+    title = '%s RSS Feed' % clist.long_name()
+    if significant:
+        subtitle = 'Document significant changes'
+    else:
+        subtitle = 'Document changes'
+
+    return render_to_response('community/public/atom.xml',
+                              {'cl': clist,
+                               'entries': notifications[:20],
+                               'title': title,
+                               'subtitle': subtitle,
+                               'id': feed_id.get_urn(),
+                               'updated': datetime.datetime.today(),
+                              },
+                              mimetype='text/xml',
+                              context_instance=RequestContext(request))
+
+
+def changes_personal_list(request, secret):
+    clist = get_object_or_404(CommunityList, secret=secret)
+    return _atom_view(request, clist)
+
+
+def changes_group_list(request, acronym):
+    group = get_object_or_404(Group, acronym=acronym)
+    clist = get_object_or_404(CommunityList, group=group)
+    return _atom_view(request, clist)
+
+
+def significant_personal_list(request, secret):
+    clist = get_object_or_404(CommunityList, secret=secret)
+    return _atom_view(request, clist, significant=True)
+
+
+def significant_group_list(request, acronym):
+    group = get_object_or_404(Group, acronym=acronym)
+    clist = get_object_or_404(CommunityList, group=group)
+    return _atom_view(request, clist, significant=True)
+
+
+def _csv_list(request, clist):
+    display_config = clist.get_display_config()
+    response = HttpResponse(mimetype='text/csv')
+    response['Content-Disposition'] = 'attachment; filename=draft-list.csv'
+
+    writer = csv.writer(response, dialect=csv.excel, delimiter=',')
+    header = []
+    fields = display_config.get_all_fields()
+    for field in fields:
+        header.append(field.description)
+    writer.writerow(header)
+
+    for doc in clist.get_documents():
+        row = []
+        for field in fields:
+            row.append(field().get_value(doc, raw=True))
+        writer.writerow(row)
+    return response
+
+
+def csv_personal_list(request):
+    user = request.user
+    if not user.is_authenticated():
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    clist = CommunityList.objects.get_or_create(user=user)[0]
+    if not clist.check_manager(user):
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    return _csv_list(request, clist)
+
+
+def csv_group_list(request, acronym):
+    group = get_object_or_404(Group, acronym=acronym)
+    if group.type.slug not in ('area', 'wg'):
+        raise Http404
+    clist = CommunityList.objects.get_or_create(group=group)[0]
+    if not clist.check_manager(request.user):
+        path = urlquote(request.get_full_path())
+        tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+    return _csv_list(request, clist)
+
+
+def _subscribe_list(request, clist, significant):
+    success = False
+    if request.method == 'POST':
+        form = SubscribeForm(data=request.POST, clist=clist, significant=significant)
+        if form.is_valid():
+            form.save()
+            success = True
+    else:
+        form = SubscribeForm(clist=clist, significant=significant)
+    return render_to_response('community/public/subscribe.html',
+                              {'cl': clist,
+                               'form': form,
+                               'success': success,
+                              },
+                              context_instance=RequestContext(request))
+
+
+def _unsubscribe_list(request, clist, significant):
+    success = False
+    if request.method == 'POST':
+        form = UnSubscribeForm(data=request.POST, clist=clist, significant=significant)
+        if form.is_valid():
+            form.save()
+            success = True
+    else:
+        form = UnSubscribeForm(clist=clist, significant=significant)
+    return render_to_response('community/public/unsubscribe.html',
+                              {'cl': clist,
+                               'form': form,
+                               'success': success,
+                               'significant': significant,
+                              },
+                              context_instance=RequestContext(request))
+
+
+def subscribe_personal_list(request, secret, significant=False):
+    clist = get_object_or_404(CommunityList, secret=secret)
+    return _subscribe_list(request, clist, significant=significant)
+
+
+def subscribe_group_list(request, acronym, significant=False):
+    group = get_object_or_404(Group, acronym=acronym)
+    clist = get_object_or_404(CommunityList, group=group)
+    return _subscribe_list(request, clist, significant=significant)
+
+
+def unsubscribe_personal_list(request, secret, significant=False):
+    clist = get_object_or_404(CommunityList, secret=secret)
+    return _unsubscribe_list(request, clist, significant=significant)
+
+
+def unsubscribe_group_list(request, acronym, significant=False):
+    group = get_object_or_404(Group, acronym=acronym)
+    clist = get_object_or_404(CommunityList, group=group)
+    return _unsubscribe_list(request, clist, significant=significant)
+
+
+def confirm_subscription(request, list_id, email, date, confirm_hash, significant=False):
+    clist = get_object_or_404(CommunityList, pk=list_id)
+    valid = hashlib.md5('%s%s%s%s%s' % (settings.SECRET_KEY, date, email, 'subscribe', significant)).hexdigest() == confirm_hash
+    if not valid:
+        raise Http404
+    (subscription, created) = EmailSubscription.objects.get_or_create(
+        community_list=clist,
+        email=email,
+        significant=significant)
+    return render_to_response('community/public/subscription_confirm.html',
+                              {'cl': clist,
+                               'significant': significant,
+                              },
+                              context_instance=RequestContext(request))
+
+
+def confirm_significant_subscription(request, list_id, email, date, confirm_hash):
+    return confirm_subscription(request, list_id, email, date, confirm_hash, significant=True)
+
+
+def confirm_unsubscription(request, list_id, email, date, confirm_hash, significant=False):
+    clist = get_object_or_404(CommunityList, pk=list_id)
+    valid = hashlib.md5('%s%s%s%s%s' % (settings.SECRET_KEY, date, email, 'unsubscribe', significant)).hexdigest() == confirm_hash
+    if not valid:
+        raise Http404
+    EmailSubscription.objects.filter(
+        community_list=clist,
+        email=email,
+        significant=significant).delete()
+    return render_to_response('community/public/unsubscription_confirm.html',
+                              {'cl': clist,
+                               'significant': significant,
+                              },
+                              context_instance=RequestContext(request))
+
+
+def confirm_significant_unsubscription(request, list_id, email, date, confirm_hash):
+    return confirm_unsubscription(request, list_id, email, date, confirm_hash, significant=True)
diff --git a/ietf/settings.py b/ietf/settings.py
index 3baeaef27..a2af787c3 100644
--- a/ietf/settings.py
+++ b/ietf/settings.py
@@ -44,12 +44,12 @@ DATABASES = {
         'USER': 'ietf',
         #'PASSWORD': 'ietf',
     },
-    'legacy': {
-        'NAME': 'ietf',
-        'ENGINE': 'django.db.backends.mysql',
-        'USER': 'ietf',
-        #'PASSWORD': 'ietf',
-    },
+#    'legacy': {
+#        'NAME': 'ietf',
+#        'ENGINE': 'django.db.backends.mysql',
+#        'USER': 'ietf',
+#        #'PASSWORD': 'ietf',
+#    },
 }
 
 # Local time zone for this installation. Choices can be found here:
@@ -86,7 +86,7 @@ ADMIN_MEDIA_PREFIX = '/media/'
 AUTH_PROFILE_MODULE = 'person.Person'
 AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.RemoteUserBackend', )
 
-DATABASE_ROUTERS = ["ietf.legacy_router.LegacyRouter"]
+#DATABASE_ROUTERS = ["ietf.legacy_router.LegacyRouter"]
 
 SESSION_COOKIE_AGE = 43200 # 12 hours
 SESSION_EXPIRE_AT_BROWSER_CLOSE = True