Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added a first stab at tracking CLAs on dp.com.

  • Loading branch information...
commit 68f56c5bf66717ff7542caea98787ba879487662 1 parent f0a023c
Jacob Kaplan-Moss jacobian authored
0  django_website/cla/__init__.py
View
No changes.
20 django_website/cla/admin.py
View
@@ -0,0 +1,20 @@
+from __future__ import absolute_import
+from django.contrib import admin
+from .models import ICLA, CCLA, CCLADesignee
+
+class ICLAAdmin(admin.ModelAdmin):
+ list_display = ['__unicode__', 'user', 'date_signed']
+ raw_id_fields = ['user']
+ ordering = ['-date_signed']
+
+class DesigneeInline(admin.StackedInline):
+ model = CCLADesignee
+ raw_id_fields = ['user']
+
+class CCLAAdmin(admin.ModelAdmin):
+ list_display = ['company_name', 'contact_name', 'contact_email', 'date_signed']
+ ordering = ['-date_signed']
+ inlines = [DesigneeInline]
+
+admin.site.register(ICLA, ICLAAdmin)
+admin.site.register(CCLA, CCLAAdmin)
143 django_website/cla/migrations/0001_initial.py
View
@@ -0,0 +1,143 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'ICLA'
+ db.create_table('cla_icla', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='iclas', null=True, to=orm['auth.User'])),
+ ('date_signed', self.gf('django.db.models.fields.DateField')()),
+ ('cla', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)),
+ ('full_name', self.gf('django.db.models.fields.CharField')(max_length=250, blank=True)),
+ ('email', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True)),
+ ('nickname', self.gf('django.db.models.fields.CharField')(max_length=250, blank=True)),
+ ('telephone', self.gf('django.db.models.fields.CharField')(max_length=50, blank=True)),
+ ('mailing_address', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('country', self.gf('django.db.models.fields.CharField')(max_length=50, blank=True)),
+ ))
+ db.send_create_signal('cla', ['ICLA'])
+
+ # Adding model 'CCLA'
+ db.create_table('cla_ccla', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('date_signed', self.gf('django.db.models.fields.DateField')()),
+ ('cla', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
+ ('company_name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ('company_address', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('country', self.gf('django.db.models.fields.CharField')(max_length=50)),
+ ('contact_name', self.gf('django.db.models.fields.CharField')(max_length=250)),
+ ('contact_email', self.gf('django.db.models.fields.EmailField')(max_length=75)),
+ ('contact_title', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ('telephone', self.gf('django.db.models.fields.CharField')(max_length=50, blank=True)),
+ ))
+ db.send_create_signal('cla', ['CCLA'])
+
+ # Adding model 'CCLADesignee'
+ db.create_table('cla_ccladesignee', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('ccla', self.gf('django.db.models.fields.related.ForeignKey')(related_name='designees', to=orm['cla.CCLA'])),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='+', null=True, to=orm['auth.User'])),
+ ('icla', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='+', null=True, to=orm['cla.ICLA'])),
+ ('date_added', self.gf('django.db.models.fields.DateField')()),
+ ('full_name', self.gf('django.db.models.fields.CharField')(max_length=250, blank=True)),
+ ('email', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True)),
+ ('nickname', self.gf('django.db.models.fields.CharField')(max_length=250, blank=True)),
+ ))
+ db.send_create_signal('cla', ['CCLADesignee'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'ICLA'
+ db.delete_table('cla_icla')
+
+ # Deleting model 'CCLA'
+ db.delete_table('cla_ccla')
+
+ # Deleting model 'CCLADesignee'
+ db.delete_table('cla_ccladesignee')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'cla.ccla': {
+ 'Meta': {'object_name': 'CCLA'},
+ 'cla': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'company_address': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'company_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'contact_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+ 'contact_name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+ 'contact_title': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'country': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'date_signed': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'telephone': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'})
+ },
+ 'cla.ccladesignee': {
+ 'Meta': {'object_name': 'CCLADesignee'},
+ 'ccla': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'designees'", 'to': "orm['cla.CCLA']"}),
+ 'date_added': ('django.db.models.fields.DateField', [], {}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'full_name': ('django.db.models.fields.CharField', [], {'max_length': '250', 'blank': 'True'}),
+ 'icla': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['cla.ICLA']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nickname': ('django.db.models.fields.CharField', [], {'max_length': '250', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['auth.User']"})
+ },
+ 'cla.icla': {
+ 'Meta': {'object_name': 'ICLA'},
+ 'cla': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'country': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
+ 'date_signed': ('django.db.models.fields.DateField', [], {}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'full_name': ('django.db.models.fields.CharField', [], {'max_length': '250', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mailing_address': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'nickname': ('django.db.models.fields.CharField', [], {'max_length': '250', 'blank': 'True'}),
+ 'telephone': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'iclas'", 'null': 'True', 'to': "orm['auth.User']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['cla']
0  django_website/cla/migrations/__init__.py
View
No changes.
104 django_website/cla/models.py
View
@@ -0,0 +1,104 @@
+"""
+Track signed CLAs.
+"""
+
+from django.db import models
+from django.contrib.auth.models import User
+
+class ICLA(models.Model):
+ """
+ An indivudal's CLA.
+
+ Since we have to deal with some legacy data this is a bit more tricky
+ than it has to be. Ideally we'd relate each CLA to a User so we can
+ see that info in Trac, but we've got a set of CLAs in paper/PDF form
+ that need to be imported and related to individuals. Thus most fields
+ here will have to be optional to accomdate this unclean data.
+
+ As we switch to e-sign we'll make most of this stuff required at the
+ *form* level, and clean up legacy data as we can. Eventually this'll
+ get trimmed down to a more clean set of fields.
+ """
+ user = models.ForeignKey(User, related_name='iclas', blank=True, null=True)
+ date_signed = models.DateField()
+ cla = models.FileField(upload_to='cla', blank=True)
+
+ # I'm not clear if all of these are actually required by law or anything,
+ # but they're the fields on the CLA forms, so we'll include them here but
+ # make them optional in case we choose to drop them in the future. These
+ # *do* duplicate some of the fields on the user model, but copying them over
+ # is a PITA so we don't for now.
+ full_name = models.CharField(max_length=250, blank=True)
+ email = models.EmailField(blank=True)
+ nickname = models.CharField(max_length=250, blank=True)
+ telephone = models.CharField(max_length=50, blank=True)
+ mailing_address = models.TextField(blank=True)
+ country = models.CharField(max_length=50, blank=True)
+
+ class Meta(object):
+ verbose_name = 'individual CLA'
+ verbose_name_plural = 'individual CLAs'
+
+ def __unicode__(self):
+ return unicode(self.full_name or self.user)
+
+class CCLA(models.Model):
+ """
+ A corporate CLA.
+
+ Caveats are as above. However, we're a little stricter out of the box about
+ CCLAs even with legacy data. Corporate contributions are a bit of a bigger
+ deal legally, and we have fewer of them, so we'll be more careful.
+ """
+ # Required fields, as for iCLA.
+ date_signed = models.DateField()
+ cla = models.FileField(upload_to='cla')
+
+ # These are duplicated in the cCLA form, but they're also rather important
+ # to be easily accessible, so we'll make them required here.
+ company_name = models.CharField(max_length=200)
+ company_address = models.TextField(blank=True)
+ country = models.CharField(max_length=50)
+ contact_name = models.CharField(max_length=250)
+ contact_email = models.EmailField()
+ contact_title = models.CharField(max_length=200)
+ telephone = models.CharField(max_length=50, blank=True)
+
+ class Meta(object):
+ verbose_name = 'corporate CLA'
+ verbose_name_plural = 'corporate CLAs'
+
+ def __unicode__(self):
+ return self.company_name
+
+class CCLADesignee(models.Model):
+ """
+ An individual whose contrbutions are covered by a CCLA.
+
+ Again caveats as above. One aditional wrinkle here is that ideally CCLA
+ signers will *also* sign an ICLA; a future version of this app might
+ want to enforce that.
+ """
+ ccla = models.ForeignKey(CCLA, related_name='designees')
+ user = models.ForeignKey(User, related_name='+', blank=True, null=True)
+ icla = models.ForeignKey(ICLA, related_name='+', blank=True, null=True)
+ date_added = models.DateField()
+ full_name = models.CharField(max_length=250, blank=True)
+ email = models.EmailField(blank=True)
+ nickname = models.CharField(max_length=250, blank=True)
+
+ class Meta(object):
+ verbose_name = 'CCLA designee'
+ verbose_name_plural = 'CCLA designees'
+
+ def __unicode__(self):
+ return unicode(self.full_name or self.user)
+
+def find_agreements(user):
+ """
+ Find any CLAs covering the given user.
+
+ Returns a list of ICLA/CCLADesignee objects covering the given user.
+ """
+ return list(ICLA.objects.filter(user=user)) + \
+ list(CCLADesignee.objects.filter(user=user))
3  django_website/settings/www.py
View
@@ -64,6 +64,7 @@
'django_push.subscriber',
'django_website.blog',
'django_website.aggregator',
+ 'django_website.cla',
'django_website.docs',
'registration',
'south',
@@ -81,7 +82,7 @@
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.common.CommonMiddleware',
- 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
+ #'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
]
if PRODUCTION:
9 django_website/urls/www.py
View
@@ -14,6 +14,8 @@
from ..blog.feeds import WeblogEntryFeed
from ..sitemaps import FlatPageSitemap, WeblogSitemap
+admin.autodiscover()
+
comments_info_dict = {
'queryset': Comment.objects.filter(is_public=True).order_by('-submit_date'),
'paginate_by': 15,
@@ -64,10 +66,3 @@
"document_root": settings.MEDIA_ROOT,
}),
)
-
-urlpatterns += patterns('',
-# flatpages need to be last b/c they match anything
- (r'', include('django.contrib.flatpages.urls')),
-)
-
-admin.autodiscover()
Please sign in to comment.
Something went wrong with that request. Please try again.